自定义类型之联合体,枚举

在这里插入图片描述

🎉welcome to my blog
请留下你宝贵的足迹吧(点赞👍评论📝收藏⭐)

1.联合体

1.1 联合体类型的声明

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

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

给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

在这里插入图片描述

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

1.2 联合体的特点

联合的成员是共用同⼀块内存空间的,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
在这里插入图片描述
在这里插入图片描述

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

1.4 联合体大小的计算

须知📚:

• 联合体的大小至少是最大成员的大小,但不一定是最大成员的大小。

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

#include<stdio.h>
union Un
{
	char c[5];//占5个字节
	//对齐数按char类型来算,故对齐数为1(1<8)
	int i;//4个字节
	//对齐数为4(4<8)
	//最大成员大小5不是最大对齐数4的整数倍,
	//就要对齐到最大对齐数4的整数倍8(8>5)处,浪费了3个字节
};
int main()
{
	union Un u = { 0 };
	printf("%zd\n", sizeof(u));
	return 0;
}
#include<stdio.h>
union Un
{
	short s[7];//一个short为2个字节,7个short为14个字节
	//对齐数按short类型来算,故对齐数为2(2<8)
	int i;//4个字节
	//对齐数为4(4<8)
	//最大成员大小14不是最大对齐数4的整数倍,
	//故要对齐到最大对齐数4的整数倍16(16>14)处,浪费了2个字节
};
int main()
{
	union Un u = { 0 };
	printf("%zd\n", sizeof(u));
	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 Mug//未匿名
		{
			char design[30];//设计 
		}mug;
		struct
		{
			char design[30];//设计 
			int colors;//颜⾊ 
			int sizes;//尺⼨ 
		}shirt;
	}item;
};

1.5 练习

//写⼀个程序,判断当前机器是大端?还是⼩端?
#include<stdio.h>
int check_sys()
{
	int n = 1;
	return *(char*)&n;//返回第一个字节,若为1是小端,若为0是大端 
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

在这里插入图片描述

//以上代码可以用联合体完成🤩
#include<stdio.h>
int check_sys()
{
union
{
		int i;
		char c;
}un;
	un.i = 1;
	return un.c;//un.i与un.c起始地址一样,故return un.c;相当于返回un.i第一个字符
	//返回1是小端,返回0是大端 
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

2.枚举类型

2.1 枚举类型的声明

枚举顾名思义就是⼀⼀列举。

把可能的取值⼀⼀列举。

比如我们现实生活中:
⼀周的星期⼀到星期日是有限的7天,可以⼀⼀列举 
性别有:男、女、保密,也可以⼀⼀列举 
月份有12个月,也可以⼀⼀列举 
三原色,也是可以一 一列举 
这些数据的表示就可以使用枚举。

枚举的关键字是enum

#include<stdio.h>
enum Color//颜色
{
	//三原色的可能取值
	RED,
	GREEN,
	BLUE
};
enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

以上定义的 enum Color,enum Sex,enum Day 都是枚举类型。

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

这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

2.2 枚举类型的使用

#include<stdio.h>
enum Color//颜色
{    //三原色的可能取值    
	RED,    
	GREEN,    
	BLUE
};
int main()
{   
	enum Color color = RED;//创建颜色变量color,并给其赋初值RED
    //赋enum Color{}中的可能取值
    return 0;
}
#include<stdio.h>
enum Color//颜色
{
	//三原色的可能取值 - 枚举常量不可更改
	//但可在创建时给其赋初始值
	//对其赋初始值时默认为0 1 2(依次增加一)
	RED=5,//赋初始值
	GREEN,
	BLUE
};
int main()
{
	//RED = 5;//error
	printf("%d\n", RED);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);
	return 0;
}

在这里插入图片描述

2.3枚举类型的优点

枚举的优点:

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

    //举例解释一下📚:
    //计算机的框架
    #include<stdio.h>
    void menu() 
    {
    	printf("**************************\n");
    	printf("****	1. add	2.sub ****\n");
    	printf("****	3. mul	4.div ****\n");
    	printf("****	    0. exit	  ****\n");
    	printf("**************************\n");
    }
    int main() {
    	int input = 0;
    		printf("请选择:>"); 
    	scanf("%d",&input); 
    	switch (input)
    	{
    		//当设计执行相关任务部分的代码时要将1,2,3,4分别与 add,sub,mul,div对应上
    		//有点小麻烦,此处可借助枚举
    	case 1:
    	    //执行相关任务
    		break;
    	case 2:
    		//执行相关任务
    		break;
    	case 3:
    		//执行相关任务
    		break;
    	case 4:
    		//执行相关任务
    		break;
    	case 0:
    		break;
    	default:
    		break;
    	}
    	return 0;
    }
    //以上代码可替换为
    #include<stdio.h>
    void menu()
    {
    	printf("**************************\n");
    	printf("****	1. add	2.sub ****\n");
    	printf("****	3. mul	4.div ****\n");
    	printf("****	    0. exit	  ****\n");
    	printf("**************************\n");
    }
    enum Option
    {
    	EXIT,
    	ADD,
    	SUB,
    	MUL,
    	DIV
    };
    int main() {
    	int input = 0;
    	printf("请选择:>");
    	scanf("%d", &input);
    	switch (input)
    	{
    		//EXIT,ADD,SUB,MUL,DIV默认对应值分别为0, 1, 2, 3, 4
    		//当设计执行相关任务部分的代码时就比较直观了
    		//不需要考虑将1,2,3,4分别与add,sub,mul,div对应的问题了
            //增加代码的可读性和可维护性    
    	case ADD:
    		//执行相关任务
    		break;
    	case SUB:
    		//执行相关任务
    		break;
    	case MUL:
    		//执行相关任务
    		break;
    	case DIV:
    		//执行相关任务
    		break;
    	case 0:
    		break;
    	default:
    		break;
    	}
    	return 0;
    }
    
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨

    enum Sex//性别
    {
    	MALE,
    	FEMALE,
    	SECRET
    };
    int main()
    {
    	enum Sex s = 0;//⚠️
        //枚举有类型检查
    	//int类型的值不能用于初始化Sex类型的实体
    	return 0;
    }
    
  3. 便于调试,预处理阶段会删除 #define 定义的符号

#define MALE 0
#define FEMALE 1
#define SECRET 2

int main()
{
	int sex =MALE;//在预处理阶段编译器会把MALE替换成0,调试时sex的值为0
    //看到的与调试的不一样
	return 0;
}
  1. 使用方便,⼀次可以定义多个常量

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

💓期待你的一键三连,你的鼓励是我创作的动力之源💓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

engrave行而不辍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值