C语言【自定义类型——枚举与联合】详细!!

目录

1、枚举 

1.0、什么是枚举

1.1、枚举类型的优点

2、联合体(共用体)

2.0、什么是联合体

2.1、联合体的特点

2.2、联合体大小的计算

2.2.0、联合体节省空间例子

2.3、联合小练习


1、枚举 

1.0、什么是枚举

枚举,顾名思义,就是一一列举,比如一周星期一到星期天,月份一一列举,又比如颜色列举等等。

在C语言中,枚举的基本语法如下:

● 定义的enum 枚举名 是枚举类型。

{ }中的内容是枚举类型的可能取值,也叫枚举常量 。

注意,枚举常量是不能被修改的。但是可以在定义里赋初值。 

enum 枚举名 {  
    枚举成员1,  
    枚举成员2,  
    ...  
    枚举成员N  
};

默认情况下,枚举成员的值从0开始递增,但我们也可以指定某个枚举成员的值,此时后续成员的值会在此基础上递增。

✅在这个例子中,Color是枚举的名称,而RED、GREEN和BLUE是枚举的成员。默认情况下,RED的值为0,GREEN的值为1,BLUE的值为2。

#include<stdio.h>
enum Color {
	RED , 
	GREEN ,
	BLUE
};
int main()
{

	enum Color color1 = RED;
	enum Color color2 = GREEN;
	enum Color color3 = BLUE;
	printf("%d\n", RED); // 0
	printf("%d\n",GREEN); //1
	printf("%d\n", BLUE); //2
	return 0;
}

如果指定某个成员的值,后面成员的值依次递增:

1.1、枚举类型的优点

我们本来可以使用#define 定义常量,为什么非要使用枚举呢?

枚举的优点:

1. 增加代码的可读性和可维护性

比如,比如我要写一个计算器-完成整数的加法、减法、乘法、除法时,可以使用枚举类型来定义ADD、SUB等,而不是使用整数1、2等来表示。这样,当看到ADD时,我们可以立即知道它代表的是加法,而无需去查看整数对应的含义。

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

使用#define宏定义标识符时,预处理器只是简单地将宏名称替换为其对应的值,由于这种替换是在编译之前进行的,并且没有类型信息,因此编译器无法对使用这些宏的变量进行类型检查。而枚举则不同,枚举是一种类型,它定义了一组命名的整型常量。当尝试将一个非枚举类型的值赋给枚举类型的变量时,编译器会进行类型检查,并可能发出警告或错误。

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

4. 使用方便,一次可以定义多个常量。

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

2、联合体(共用体)

2.0、什么是联合体

● 像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型

● 但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体

● 这意味着,当你给联合体的一个成员赋值时,其他成员的值会被覆盖,因为它们共享同一块内存空间。

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

 运行结果:4

2.1、联合体的特点

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

#include <stdio.h>
//联合类型的声明
union Un
{
	char c;
	int i;
};
int main()
{
	union Un un = { 0 };
	printf("%p\n", &un);
	printf("%p\n", &(un.i));
	printf("%p\n", &(un.c));
	
	return 0;
}

运行结果:输出的三个地址一模一样。可见联合的成员是共用同一块内存空间的

✅也可以通过下面这段代码来调试观察:

#include <stdio.h>
//联合类型的声明
union Un
{
	char c;
	int i;
};
int main()
{
	union Un un = { 0 };
	un.i = 0x11223344;
	un.c = 0x55;

	return 0;
}

内存观察: 

i 的第4个字节的内容修改为55了。un 的内存布局图:

2.2、联合体大小的计算

联合的大小至少是最大成员的大小。注意(是至少,但不一定)

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

✅代码: 

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

如上面Un1中算出最大对齐数是4 ,但最大成员大小是5,所以要对齐到最大对齐数4 的整数倍,结果是8 。算Un2的大小也是一样的思路。

2.2.0、联合体节省空间例子

使用联合体是可以节省空间的。

比如:

我们要组织一个活动,参与者可以通过积分兑换三种不同的奖励:虚拟游戏皮肤、实体纪念品、和赛事访问权限

每种奖励都有一些共同的属性:库存量、所需的积分、奖励类型,以及每种类型特有的其他信息。

其他信息:

虚拟游戏皮肤:皮肤名称、设计
实体纪念品:尺寸、设计、颜色
赛事访问权限:参赛人数

 ✅结构如下:

struct point_list
{
	//公共属性
	int stock_number;//库存量
	double points; //所需积分
	int reward_type;//奖励类型

	//特殊属性
	char title[20];//皮肤名称
	char design[30];//设计
	int sizes;//尺⼨
	int colors;//颜⾊
	int num_participant;//参赛人数

};

上述的结构设计简单,用起来方便,但是结构的设计中包含了所有奖励的各种属性,这样使得结构体的大小偏大,比较浪费内存。

因为对于积分兑换单中的奖励来说,只有部分属性信息是常用的。

比如: 奖励是实体纪念品时,就不需要num_participant,因为它是赛事访问权限的特有信息。 所以我们就可以把公共属性单独写出来,剩余属于各种奖励本身的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。

代码:

struct point_list
{
	//公共属性
	int stock_number;//库存量
	double points; //所需积分
	int reward_type;//奖励类型
	union {
		struct
		{
			char title[20];//皮肤名称
			char design[30];//设计
		}game_skin;
		struct
		{
			
			int sizes;//尺⼨
			int colors;//颜⾊
			char design[30];//设计
		}souvenir;
		struct
		{
			int num_participant;//参赛人数
		}rights;
	}reward;

};

2.3、联合小练习

✅写一个程序,判断当前机器是大端?还是小端?这个练习之前也做过,现在我们运用联合体知识实现。

#include<stdio.h>
union Un
{
	char c;
	int i;
};

int main()
{
	union Un un = { 0 };
	un.i = 1; 
	if (un.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

⛳ 点赞☀收藏 ⭐ 关注!

如有不足欢迎评论区指出!

Respect!!!

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值