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

一.联合体

1.联合体的声明

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

cpp 复制代码
#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.联合体的特点

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

cpp 复制代码
//代码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

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

cpp 复制代码
//代码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.相同成员的结构体和联合体对比

cpp 复制代码
struct S
{
 char c;
 int i;
};
struct S s = {0};

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

cpp 复制代码
union Un
{
 char c;
 int i;
};
union Un un = {0};

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

4.联合体大小的计算

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

cpp 复制代码
#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;
}

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

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

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

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

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

下面我们来实现该代码:

cpp 复制代码
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。 所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。

cpp 复制代码
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.联合体习题

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

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

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

二.枚举类型

1.枚举类型的声明

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

cpp 复制代码
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,当然在声明枚举类型的时候也可以赋初值。比如下面的代码:

cpp 复制代码
enum Color//颜⾊
{
 RED=2,
 GREEN=4,
 BLUE=8
};

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

2.枚举类型的优点

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

枚举的优点:

  1. 增加代码的可读性和可维护性,将数值赋予对应的含义,代码意义就会更加清晰。
cpp 复制代码
#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代表的是什么了。

  1. 和#define定义的标识符比较枚举有类型检查,更加严谨。
cpp 复制代码
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++语言上这样操作。

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

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

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

3.枚举类型的使用

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

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

相关推荐
小xin过拟合1 小时前
day20 二叉树part7
开发语言·数据结构·c++·笔记·算法
啟明起鸣2 小时前
【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
c语言·开发语言·数据结构
十八旬2 小时前
苍穹外卖项目实战(日记十)-记录实战教程及问题的解决方法-(day3-2)新增菜品功能完整版
java·开发语言·spring boot·mysql·idea·苍穹外卖
这周也會开心3 小时前
Java-多态
java·开发语言
Forward♞3 小时前
Qt——网络通信(UDP/TCP/HTTP)
开发语言·c++·qt
2401_858286113 小时前
OS26.【Linux】进程程序替换(下)
linux·运维·服务器·开发语言·算法·exec·进程
草莓熊Lotso3 小时前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day13
c语言·开发语言·刷题·强化训练
一尘之中4 小时前
在Python 2.7中安装SQLAlchemy的完整指南
开发语言·python·ai写作
刃神太酷啦5 小时前
Linux 常用指令全解析:从基础操作到系统管理(1w字精简版)----《Hello Linux!》(2)
linux·运维·服务器·c语言·c++·算法·leetcode