完整教程:C语言自学--自定义类型:联合和枚举
目录
1、联合体
- 1.1 、联合体类型的声明
与结构体类似,联合体也是由多个成员组成,这些成员可以是不同类型。但其独特之处在于:
- 编译器仅按最大成员所需空间分配内存
- 所有成员共享同一块内存空间
- 当修改任一成员值时,其他成员的值也会随之改变
因此联合体也被称为"共用体"。
-  #include//联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = { 0 }; //计算连个变量的⼤⼩ printf("%d\n", sizeof(un)); return 0; } 
联合类型的特点是所有成员共享同一块内存空间,联合的大小等于其最大成员的大小。在这个例子中:
- char c占用1字节
- int i在大多数系统上占用4字节
- 因此整个联合 un的大小为4字节
- 1.2、联合体的特性
联合体的所有成员共享同一块内存空间,因此联合体变量的大小至少等于其最大成员的尺寸(必须确保能够容纳最大的数据成员)。
-  //代码1 #include//联合类型的声明 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; } 
输出结果:

-  //代码2 #include//联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = { 0 }; un.i = 0x11223344; un.c = 0x55; printf("%x\n",un.i);//十六进制: %x (小写) / %X (大写) return 0; } 输出结果: 11223355代码1输出的三个地址一模一样,代码2的输出,我们发现将i的第4个字节的内容修改为55了。 我们仔细分析就可以画出,un的内存布局图。 

- 1.3 、相同成员的结构体和联合体对比
让我们对比一下相同成员的结构体和联合体的内存布局差异。
-  struct S { char c; int i; }; struct S s = {0};
-  union Un { char c; int i; }; union Un un = { 0 };

- 1.4、联合体大小的计算方法
1、联合的大小至少是最大成员的大小。
2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
-  #includeunion Un1 { char c[5]; //5 1 8 1 int i; //4 8 4 }; union Un2 { short c[7];//14 2 8 2 int i; // 4 8 4 }; int main() { //下⾯输出的结果是什么? printf("%d\n", sizeof(union Un1));//8 最大对齐数是4,他的2倍数刚好>=5 printf("%d\n", sizeof(union Un2));//16 最大对齐数是4,他的4倍数刚好>=14 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];//设计
		}cup;
		struct
		{
			char design[30];//设计
			int colors;		//颜色
			int sizes;		//尺寸
		}shirt;
	};
};
int main() {
	struct gift_list item1;
	item1.stock_number = 50;
	item1.price = 19.99;
	item1.item_type = 1;
	strcpy(item1.book.title, "C Programming");//把C Programming字符串复制到book对象中的title
	strcpy(item1.book.author, "K&R");	//把K&R复制到book对象中的author
	item1.book.num_pages = 300;
	printf("Book: %s by %s, %d pages\n", item1.book.title, item1.book.author, item1.book.num_pages);
	return 0;
}- 1.5、联合的一个练习
写一个程序,判断当前机器是大端?还是小端?
//判断是大端还是小端
#include 
int main()
{
	int a = 1;
	//00 00 00 01  大端
	//01 00 00 00  小端
	//把int强转为char判断第一个字节是不是为1就行
	if (*(char*)&a ==1)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
} 方法二:
//判断是大端还是小端
#include 
union Un
{
	char c;
	int i;
}un;
int main()
{
	//00 00 00 01  大端
	//01 00 00 00  小端
	un.i = 1;
	if (un.c ==1)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
} 2、枚举类型
- 2.1、枚举类型声明
枚举是一种将可能取值一一列出的数据类型。例如生活中的常见场景:
- 一周七天(周一到周日)
- 性别分类(男、女、保密)
- 十二个月份
- 三原色(红、黄、蓝)
这些具有明确范围的离散值,都可以通过枚举来清晰表示。
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	sun
};
enum Sex //性别
{
	MALE,
	FAMALE,
	SECRET
};
enum Color//颜⾊
{
	RED,
	GREEN,
	BLUE
};上面定义的enum Day,enum Sex,enum Color都是枚举类型。{}中的内容是枚举类型的可能取值,也叫 枚举常量。 这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。
enum Color//颜⾊
{
	RED = 2,
	GREEN = 4,
	BLUE = 8
};- 2.2、枚举类型的优势
为什么要使用枚举?虽然可以使用#define定义常量,但枚举具有以下优势:
#define MALE 3
#define FEMALE 5
#define SECRET 7enum Sex
{
    //该枚举类型的三种可能取值
    //他们都是常量,被称为枚举常量
    MALE 3, //0 默认0开始
    FEMALE 5,//1
    SECRET 7 //2
};- 增加代码的可读性和可维护性
- 相比#define定义的标识符,枚举具有类型检查功能,更加严谨可靠
- 便于调试,预处理阶段会删除 #define 定义的符号
- 使用更便捷,可以一次性定义多个相关常量
- 遵循作用域规则,在函数内声明的枚举仅在该函数内有效
- 2.3、枚举类型的应用
enum Color//颜⾊
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
enum Color clr1 = GREEN;//使⽤枚举常量给枚举变量赋值
enum Color clrw = 2;//C语言中可以,但c++不行,因为这是把一个整型赋值给一个enum Color枚举类型能否用整数直接给枚举变量赋值?在C语言中是允许的,但C++不支持这种操作,因为C++的类型检查机制更为严格。
-  enum Color clrw = 2;
C语言中可以,因为C语言类型审查不严格,但c++不行,因为这是把一个整型2赋值给一个enum Color枚举类型。
#include 
enum Option
{
	Exit,//0
	Add,//1
	Sub,
	Mul,
	Div
};
void menu()
{
	printf("**************************************\n");
	printf("********** 0.Exit   1.Add  ***********\n");
	printf("********** 2.Sub    3.Mul  ***********\n");
	printf("********** 2.Div    0.Exit ***********\n");
	printf("**************************************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			break;
		case Sub:
			break;
		case Mul:
			break;
		case Div:
			break;
		case Exit:
			break;
		default:
			printf("输入错误,请重新输入:\n");
			break;
		}
	} while (input);
	return 0;
} #include 
enum Option
{
	EXIT,//0
	ADD,//1
	SUB,
	MUL,
	DIV
};
int Add(int x,int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
void menu()
{
	printf("**************************************\n");
	printf("********** 0.Exit   1.Add  ***********\n");
	printf("********** 2.Sub    3.Mul  ***********\n");
	printf("********** 4.Div    0.Exit ***********\n");
	printf("**************************************\n");
}
int main()
{
	int input = 0;
	int num1, num2, result;
	do
	{
		menu();
		printf("请选择运算方法:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			printf("请输入要操作的两个数:");
			scanf("%d %d", &num1, &num2);
			result = Add(num1, num2);
			printf("计算结果为:%d\n",result);
			break;
		case SUB:
			printf("请输入要操作的两个数:");
			scanf("%d %d", &num1, &num2);
			result = Sub(num1, num2);
			printf("计算结果为:%d\n", result);
			break;
		case MUL:
			printf("请输入要操作的两个数:");
			scanf("%d %d", &num1, &num2);
			result = Mul(num1, num2);
			printf("计算结果为:%d\n", result);
			break;
		case DIV:
			printf("请输入要操作的两个数:");
			scanf("%d %d", &num1, &num2);
			result = Div(num1, num2);
			printf("计算结果为:%d\n", result);
			break;
		case EXIT:
			break;
		default:
			printf("输入错误,请重新输入:\n");
			break;
		}
	} while (input);
	return 0;
}  
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号