当前位置: 首页 > news >正文

C语言第十三章自定义类型:联合和枚举

一.联合体

1.联合体的声明

        像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体。 给联合体其中一个成员赋值,其他成员的值也会跟着变化(因为所有成员共用一个空间)。

#include <stdio.h>
//联合类型的声明 
union Un
{char c;int i;
};
int main()
{//联合变量的定义 union Un un = {0};//计算连个变量的⼤⼩ printf("%d\n", sizeof(un));return 0;
}

        上述代码的具体解释:首先进行了联合体的声明,两个联合体成员变量c和i共处一个空间中。其次进入main函数,创建了联合体变量un,并初始化为0。最后利用操作符sizeof来计算联合体变量un的大小。

        上述代码输出的结果:4,为什么呢?请继续阅读下面的相关解释:

2.联合体的特点

        联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合体至少得有能力保存最大的那个联合体成员)。

//代码1 
#include <stdio.h>
//联合类型的声明 
union Un
{char c;int i;
};
int main()
{//联合变量的定义 union Un un = {0};// 下⾯输出的结果是⼀样的吗? printf("%p\n", &(un.i));printf("%p\n", &(un.c));printf("%p\n", &un);return 0;
}

001AF85C

001AF85C

001AF85C

        通过上述代码的输出结果来看:联合体的变量都公用一份空间,所有的联合体变量的内存数都一样。

//代码2 
#include <stdio.h>
//联合类型的声明 
union Un
{char c;int i;
};
int main()
{//联合变量的定义 union Un un = {0};un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);return 0;
}

11223355

        通过上述代码的输出情况可以看出:联合体的所有成员公用一块内存,当一个变量的值发生变化时,其余变量也会因此而受影响。

        代码1输出的三个地址一模一样,代码2的输出,我们发现将i的第4个字节的内容修改为55。我们仔细分析就可以画出,un的内存布局图。

3.相同成员的结构体和联合体对比

struct S
{char c;int i;
};
struct S s = {0};

        结构体通过内存对齐,用空间换取时间和效率。保证一次CPU的内存读取可以成功读取一个变量的数据。

union Un
{char c;int i;
};
union Un un = {0};

        联合体注重空间的节省,通过将所有变量存在一个内存块中,从而达到节省空间的目的。

4.联合体大小的计算

        联合的大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{//下⾯输出的结果是什么? printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}

        根据上方图片可得知:联合体并不是不浪费丝毫空间,其本身也存在内存对齐。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。下面来一个联合体的实用场景,用于加深对知识的理解:

        使用联合体是可以节省空间的,比如:学校要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。 每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:库存量、价格、商品类型、商品类型、书名、作者、页数;

杯子:库存量、价格、商品类型、商品类型、设计;

衬衫:库存量、价格、商品类型、商品类型、设计、可选颜色、可选尺存。

下面我们来实现该代码:

struct gift_list
{//公共属性 int stock_number;//库存量 double price; //定价 int item_type;//商品类型 //特殊属性char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ 
}

        上述的结构其实设计的很简单,用起来也方便,就是将所有的属性均放在结构体中,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常用的。比如: 商品是图书,就不需要design、colors、sizes。 所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。

struct gift_list
{int stock_number;//库存量 double price; //定价 int item_type;//商品类型 union {struct{char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 }book;struct{char design[30];//设计 }mug;struct {char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ }shirt;}item;
}

        上述代码首先将共有的属性充当结构体的成员,当需要某些特殊属性时,则将联合体定义在结构体中,将每个特殊属性的组合新分配到小结构体中作为联合体成员。这也满足了联合体一次只能得到一个成员变量的特点。

        上述代码充分利用了结构体和联合体的特点,将可以一同取出数据的结构体成员定义为共同属性;将一次只能得到一个成员的联合体成员定义为特殊属性。

5.联合体习题

        写一个程序,判断当前机器是大端?还是小端?

int check_sys()
{union{int i;char c;}un;un.i = 1;return un.c;//返回1是⼩端,返回0是⼤端 
}

        上述代码利用了联合体成员变量共用一份空间的特点,巧妙地通过取出联合体成员变量c的地址而得到了,整型变量c的首字节地址。

二.枚举类型

1.枚举类型的声明

        枚举顾名思义就是一一列举。 把可能的取值一一列举。 比如我们现实生活中:一周的星期yiyi到星期天是有限的7天,可以一一列举;性别有:男、女,也可以一一列举;月份有12个月,也可以一一列举;三原色,也是可以一一列举。这些数据的表示就可以使用枚举类型。

enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
enum Sex//性别
{MALE,FEMALE
};
enum Color//三原色
{RED,GREEN,BLUE
};

        以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。 {  } 中的内容是枚举类型的可能取值,也叫枚举常量。这些枚举常量都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。比如下面的代码:

enum Color//颜⾊
{RED=2,GREEN=4,BLUE=8
};

        上述代码就是将枚举常量赋值为2 4 8 。当然如果只赋值第二个枚举常量为4,那么第一个枚举常量就为默认值:0;第三个枚举常量的值就是第二个枚举常量的值+1:5

2.枚举类型的优点

        在C语言中,可以使用 #define 定义常量,为什么还要使用枚举呢?

枚举的优点:

        1. 增加代码的可读性和可维护性,将数值赋予对应的含义,代码意义就会更加清晰。

#include <stdio.h>
void menu()
{printf("******1.jia*******2.jian*********\n");printf("******3.cheng*****4.chu**********\n");printf("******0.tuichu*******************\n");printf("***********  ********************\n");
}
int jia1(int x, int y)
{return x + y;
}
int jian1(int x, int y)
{return x - y;
}
int cheng1(int x, int y)
{return x * y;
}
int chu1(int x, int y)
{return x / y;
}
enum caozuo 
{tuichu,jia,jian,cheng,chu
};
int main()
{int input=0;do{menu();printf("请选择你需要的操作");scanf_s("%d", &input);int a, b,ret=0;printf("请输入需要参加运算的两个整数");scanf_s("%d %d", &a, &b);switch (input){case 1:		//case jia:ret = jia1(a, b);printf("计算结果为:%d\n", ret);break;case 2:		//case jian:ret = jian1(a, b);printf("计算结果为:%d\n", ret);break;case 3:		//case cheng:ret = cheng1(a, b);printf("计算结果为:%d\n", ret);break;case 4:		//case chu:ret = chu1(a, b);printf("计算结果为:%d\n", ret);break;case 0:		//case tuichu:printf("成功退出\n");break;default:printf("输入错误\n");break;}} while (input);return 0;
}

        如上述代码所示:switch语句在使用过程中,情况case语句可以写成后面的注释样子。那样可以增强代码的阅读性,在下次阅读代码时,就不需要再查看input代表的是什么了。

        2. 和#define定义的标识符比较枚举有类型检查,更加严谨。

enum Color 
{ 
RED, 
GREEN, 
BLUE 
};
Color c = RED; // 类型正确
c = 10;        // 可能触发警告或错误,因为10不是Color类型

        上述代码创建了三原色的枚举类型,默认情况下RED=0, GREEN=1, BLUE=2。接下来创建了枚举变量c,初始化为RED,但是最后却将c赋值为10,这明显是错误的。10并不是枚举常量的数值。这样会引起编译器的报错。

        这种用无关于枚举常量数值为枚举变量赋值的做法,仅仅只限于C语言,并不能在C++语言上这样操作。

        3. 便于调试,预处理阶段会删除#define定义的符号,不便于后期的调试操作。

        4. 使用方便,一次可以定义多个常量,不用一直连续写出多个#define。

        5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。

3.枚举类型的使用

enum Color//颜⾊
{RED=1,GREEN=2,BLUE=4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值 

        上述枚举类型:首先声明了枚举类型,并对其中的枚举常量进行赋值,在今后使用时,就可以将枚举常量赋值给枚举变量。

http://www.dtcms.com/a/350155.html

相关文章:

  • 高通平台WIFI学习-- 基于WCN6750 Tri-Band 2x2 MIMO 802.11ax的讲解
  • IntelliJ IDEA 新手入门教程-Java、Web、Maven创建(带图解)
  • 2025年金九银十Java面试场景题大全:高频考点+深度解析+实战方案
  • 服务器Docker 安装和常用命令总结
  • vite 项目创建、插件配置
  • [React]Antd Select组件输入搜索时调用接口
  • 第二章 数据通信基础
  • beego v2 处理全局异常
  • 文献阅读笔记:KalmanNet-融合神经网络和卡尔曼滤波的部分已知动力学状态估计
  • Canvas 内凹弧形导航菜单(顶部内凹)
  • 基于MATLAB长时间序列遥感数据处理及在全球变化、物候提取、植被变绿与固碳分析等领域中的应用
  • 权限越权概念
  • centos7 安装coze
  • 【计算星座】2022-10-24
  • 普蓝超强承重越野移动机器人底盘轻松应对复杂路段
  • 《C++进阶:引用补充、内联函数与nullptr 核心用法》
  • 3 系统设计面试的框架
  • Odoo 企业版用户手册[新版]-前言 00.1-手册说明与使用指南
  • EasyClick 生成唯一设备码
  • SP95N65CTO:一款高性能650V SiC MOSFET的全面解析
  • 数据赋能(409)——大数据——合规性和伦理性原则
  • 强化学习基础总结
  • 《分布式系统跨服务数据一致性Bug深度复盘:从现象到本质的排查与破局》
  • 2025年优化算法:雪雁优化算法(Snow Geese Algorithm,SGA)
  • 2025 JVM 并发革命:虚拟线程与结构化并发,引领性能飞跃(35)
  • 京东前端社招面经
  • Pandas 高效数据处理:apply、向量化与分组
  • Qt——多媒体(音频、视频播放)
  • 艾利特石油管道巡检机器人:工业安全的智能守护者
  • 系统数据库