【C语言】自定义类型联合和枚举讲解超详细

news2024/11/19 5:51:09

人生只有回不去的过去,没有过不去的当下。 💓💓💓

目录

•🌙知识回顾

 🍋知识点一:联合体

  • 🌰1.联合体类型的声明

 • 🌰2.联合体的特点

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

• 🌰4.联合体大小的计算

• 🌰4.联合的一个练习

 🍋知识点二:枚举类型

   • 🌰1.枚举类型的声明

​编辑 • 🌰2.枚举类型的优点

​编辑• 🌰3.枚举类型的应用

•🌙SumUp 结语


•🌙知识回顾

亲爱的友友们大家好!💖💖💖,我们接着要进入C语言自定义类型的学习,上一篇文章我们详细解析了C语言中的一种自定义类型-结构体,包含了结构体的声明、结构体变量在内存中的存储等,希望大家能够熟练应用~

    

今天给大家带来的是自定义类型-联合体和枚举类型的知识,他们都属于C语言的自定义类型,希望大家好好学习,也希望可以给大家带来帮助。

  

👇👇👇
💘💘💘知识连线时刻(直接点击即可)

  🎉🎉🎉复习回顾🎉🎉🎉
     自定义类型结构体详细讲解

  

 💘💘💘学习C语言的过程离不开刷题,这里🌷给大家推荐两个很好的学习刷题网站——力扣、牛客网,各种题目应有尽有,大家可以在上面挑选合适难度的题进行训练

👇👇👇

各位友友们!🎉🎉🎉点击这里进入牛客网🎉🎉🎉

👇👇👇

🎉🎉🎉这里是力扣🎉🎉🎉

 🍋知识点一:联合体

  • 🌰1.联合体类型的声明

像我们上一章节介绍的结构体一样,联合体也是由一个或多个成员构成,这些成员可以是不同的类型。但是编译器只为最大的成员分配足够的内存空间,而结构体的每个成员都有自己独立的空间,联合体的特点是所有的成员都共用同一块内存空间,所以联合体也叫:共用体如果我们给联合体中的其中一个成员赋值,其他成员的值也会发生变化。

结构体的关键字是struct,联合体的关键字是union。

💯代码演示:

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

	return 0;
}

其实联合体变量和结构体变量的声明和初始化是类似的,我们依葫芦画瓢就能够写出来,那重点是这个联合体变量的大小是多少呢?或者说,我们如何计算联合体的大小? 

 • 🌰2.联合体的特点

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

在讨论联合体大小之前,我们先来看一段代码:

#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;
}

结果:联合体的地址和各个联合体成员变量的地址相同。

上面输出的结果再次验证了联合变量的成员是共用同一块空间的。那大家现在应该可以想得到这个联合的大小是多少了。char 型的c和 int 型的i共用一块空间,在内存中的放置应该如下:

变量i和变量c一共占用了4个字节,其中第一个字节是共用的,或是重叠的,所以这个联合体变量的大小就是4个字节。 如果我们对i进行修改,第一个字节被修改了,那么c的值也会被更改,所以我们一般在有多个变量时,用A变量就不用B、C、D变量的时候,或用B变量就不用A、C、D变量时,此时可以用联合体。

💯代码演示:

#include <stdio.h>
union Un
{
	char c;
	int i;
};
int main()
{
	union Un un = { 0 };
	un.i = 0x11223344;
	un.c = 0x55;
	
	return 0;
}

 当创建un.i时,内存为44 33 22 11(小端存储模式),而创建un.c时,就会将内存的第一个字节修改,变成55 33 22 11

💯图解:

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

struct S                                    union Un                                       
{                                           {
    char c;                                     char c;                
	int i;                                      int i;
};                                          };

struct S s = { 0 };                         union Un un = { 0 };

💯图解:

他们空间占用是不同的,联合体会比结构体占用的空间更少,而且他们的引用场景也是不同的。

• 🌰4.联合体大小的计算

根据联合体的特点,以及我们上面的分析,可能有人就会认为说,联合体的大小就是联合体中最大的那个成员变量的大小,其实这是不对的,联合体也有和结构体类似的对齐规则。

🔥联合的大小至少是最大成员的大小。

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

💯代码演示:

#include <stdio.h>
union Un
{
	char c[5];//5
	int i;//4
};
int main()
{
	union Un u = { 0 };
	printf("%zd\n", sizeof(u));//8

	return 0;
}

💯分析:

就比如上面这段代码,联合中有一个包含5个 char 型元素的数组和一个 int 型的变量,数组中的每一个元素占1个字节,int i 占4个字节,如果说联合的大小就是最大成员的大小,那么应该是数组大小5,而上面代码的结果是8。

不知大家还记不记得上一个篇章结构体中对齐数的概念,VS上的默认对齐数是8,成员变量的对齐数是该成员变量的大小和默认对齐数的较小值,对于上面联合变量来说,对齐数分别为1和4,最大对齐数为4,5并不是4的整数倍,所以要对齐到8,上面联合体的大小为8个字节

🎉🎉🎉联合体使用场景🎉🎉🎉

使用联合体是可以节省空间的,举例:

比如,我们现在要搞一个活动,要上线一个礼品兑换单,礼品兑换单中共有三种商品:图书、杯子、衬衫

每一种商品都有:库存量、价格、商品类型(公共属性)和商品类型相关的其他信息(特有属性):

图书:书名、作者、页数

杯子:设计

衬衫:设计、可选颜色、可选尺寸

我们可以直接写出以下结构,这个结构必须包含公共属性和特有属性:
 
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;//尺寸
};

但是我们可以发现,如果用来描述书,那么设计、颜色、尺寸就不被需要;描述杯子的时候,书名、作者、页数、颜色、尺寸也不被需要;描述衬衫时,书名、作者、页数、设计不被需要。我们虽然能设计这样的一个结构体来完成任务,但是用来描述不同的商品时都造成了很大的空间浪费。所以我们就可以把公共属性单独写出来,剩余的各个商品的特殊属性使用联合体,这样就可以节省所需的内存空间,一定程度上节省了内存。

💯代码演示:

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;
};

• 🌰4.联合的一个练习

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

我在🎉🎉🎉数据在内存中的存储🎉🎉🎉中提供了一种方法:

#include <stdio.h>
int check_sys()
{
	int n = 1;
	return *(char*)&n;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

现在我用联合体的方式给出另外一种方法

💯代码演示:

#include <stdio.h>
int check_sys()
{
	union Un
	{
		int n;
		char c;
	}u;
	u.n = 1;
	return u.c;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

u.c其实就是u.i的第一个字节,我们直接返回它就好了,这个方法也是十分巧妙。

 🍋知识点二:枚举类型

   • 🌰1.枚举类型的声明

枚举类型顾名思义就是一一列举,把可能的取值一一列举。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举。

三原色,也可以一一列举。

上面这些数据的表示就可以使用枚举了。

💯代码演示:

enum Color
{
	//三原色的可能取值
	RED,
	GREEN,
	BLUE
};
enum Sex
{
	//性别的可能取值
	MALE,
	FEMALE,
	SECRET
};

注意:枚举的写法和结构、联合有些不同,枚举中可能的取值后面是逗号,并且最后一个取值后无符号。

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

💯代码1:

#include <stdio.h>
enum Color
{
	//三原色的可能取值
	RED,
	GREEN,
	BLUE
};
int main()
{
	printf("%d %d %d\n", RED, GREEN, BLUE);//0 1 2

	return 0;
}

 💯代码2:

#include <stdio.h>
enum Color
{
	//三原色的可能取值
	RED,//0
	GREEN=5,//5
	BLUE//6
};
int main()
{
	printf("%d %d %d\n", RED, GREEN, BLUE);//0 5 6

	return 0;
}

 • 🌰2.枚举类型的优点

我们可以使用 #define 定义常量,例如

#define RED 0
#define GREEN 1
#define BLUE 2

那为什么非要使用枚举?

🎉🎉🎉枚举的优点🎉🎉🎉

🔥增加代码的可读性和保护性。

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

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

🔥使用方便,依次可以定义多个常量

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

• 🌰3.枚举类型的应用

比如说我们想做一个计算器,代码如下

💯代码演示:

#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;
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//加法
			break;
		case 2:
			//减法
			break;
		case 3:
			//乘法
			break; 
		case 4:
			//除法
			break;
		case 0:
			//退出
			break;
		}
		//...
	} while (input);
}

这样做确实可以实现对应的功能,但有个不太好的地方,就是我如何将1、2、3、4和加减乘除对应呢?我如果记不住呢?那我每次都要回到 menu 去看,比较麻烦,我们可以用枚举来解决这个问题

💯代码演示:

#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;
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			//加法
			break;
		case SUB:
			//减法
			break;
		case MUL:
			//乘法
			break; 
		case DIV:
			//除法
			break;
		case EXIT:
			//退出
			break;
		}
		//...
	} while (input);
}

如果我们用枚举,那么我们看到ADD,就会联想到加法,看到SUB,就会联想到减法,看到EXIT,就会联想到退出,是个不错的方法。

•🌙SumUp 结语

C语言所有的自定义类型,包括结构、联合和枚举的学习到这里就结束啦~后面就会进入动态内存管理的学习。在这里希望大家能够将前面的C语言的的基础知识进行回顾复习,使整个纯C学习是连贯的,这样更加利于我们的学习和理解以及继续拓展。

如果大家觉得有帮助,麻烦大家点点赞,如果有错误的地方也欢迎大家指出~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1636980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux操作系统预备 —— 冯·诺伊曼体系结构

一&#xff0c;什么是冯诺伊曼体系结构&#xff1f;&#xff08;是什么&#xff1f;&#xff09; 上面的图就是冯诺伊曼体系结构的总体简略图&#xff0c;不着急&#xff0c;我们一个一个来看&#xff1a; 1.1 输入输出设备 人们要想用计算机处理数据&#xff0c;首先就要把要…

数据链路层(计算机网络)

0、前言 本文大多数图片都来自于 B站UP主&#xff1a;湖科大教书匠 的教学视频&#xff0c;对高军老师及其团队制作出这么优质的课程表示感谢。本文的撰写目的不是为了应试&#xff0c;且受限于个人水平&#xff0c;可能和标准答案有所出入&#xff0c;请自行甄别&#xff0c;…

Scikit-Learn回归树

Scikit-Learn回归树 1、决策树1.1、什么是决策树1.2、决策树学习的步骤1.3、决策树算法 1、决策树 决策树&#xff08;DTs&#xff09;是一种用于回归和分类的有监督学习方法。通常&#xff0c;决策树用于分类问题&#xff1b;当决策树用于回归问题时&#xff0c;称为回归树。回…

2024.阳光能源追光计划暨大陆考察团交流分享会

近日大陆考察团抵达香港&#xff0c;受到了本司热情接待和安排。公司于4月27日下午举办了阳光能源追光计划主题交流会。 会上公司营销部总监张超&#xff0c;分享了阳光能源近几年的能源发展之路及公司新推出的追光计划&#xff0c;得到了大陆考察交流团团长杨国均先生的高度赞…

【c++】反向迭代器的探究实现

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 在list中我们实现了正向的迭代器&#xff0c;学习完优先级队列后&#xff0c;我们也对适配器模式有了一个深刻的理解&#xff0c;这篇文章基于这种模式下&#xff0c;实现各类容器的反向迭…

基于STC12C5A60S2系列1T 8051单片机的Proteus中的单片机发送一帧或一串数据给串口调试助手软件接收区显示出来的串口通信应用

基于STC12C5A60S2系列1T 8051单片机的Proteus中的单片机发送一帧或一串数据给串口调试助手软件接收区显示出来的串口通信应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列…

2024五一数学建模竞赛(五一赛)选题建议+初步分析

提示&#xff1a;DS C君认为的难度&#xff1a;B>A>C&#xff0c;开放度&#xff1a;AB<C。 以下为A-C题选题建议及初步分析&#xff1a; A题&#xff1a;钢板最优切割路径问题 l 难度评估&#xff1a;中等难度。涉及数学建模和优化算法&#xff0c;需要设计最优的…

windows驱动开发-电源管理

驱动程序收到的电源IRP的主功能码是IRP_MJ_POWER 以及四个次要代码: IRP_MN_POWER_SEQUENCE 驱动程序将此 IRP 作为优化发送&#xff0c;以确定其设备是否实际进入了特定的电源状态。 对此 IRP 的支持是可选的。 若要发送此 IRP&#xff0c;驱动程序必须调用 IoAllocateIrp …

鸿蒙准备1

鸿蒙心路 感慨索性&#xff0c; 看看鸿蒙吧。打开官网相关介绍 新建工程目录结构 感慨 最近面试Android应用开发&#xff0c;动不动就问framework的知识&#xff0c;什么touch事件的触发源是啥&#xff08;eventHub&#xff09;&#xff0c;gc流程是啥&#xff0c;图形框架是什…

SpringCloudStream 3.x rabbit 使用

1. 前言 今天带来的是SpringCloudStream 3.x 的新玩法&#xff0c;通过四大函数式接口的方式进行数据的发送和监听。本文将通过 rabbitMQ 的方式进行演示 3.x版本后是 可以看到 StreamListener 和 EnableBinding 都打上了Deprecated 注解。后续的版本更新中会逐渐替换成函数式…

修改Ubuntu远程登录欢迎提示信息

无论何时登录公司的某些生产系统&#xff0c;你都会看到一些登录消息、警告或关于你已登录服务器的信息&#xff0c;如下所示。 修改方式 1.打开ubuntu终端,进入到/etc/update-motd.d目录下面 可以发现目录中的文件都是shell脚本, 用户登录时服务器会自动加载这个目录中的文件…

深度学习之基于Matlab NN的伦敦房价预测

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 房价预测是房地产领域的一个重要问题&#xff0c;对于投资者、开发商以及政策制定者等都具有重要的指…

【写作吗。月入过万,8年写作路,10w+订阅创作者的18条建议】

Tom Kuegler &#xff1a;62k粉丝的medium独立作者&#xff0c;全网累计10w人订阅。他不是高深莫测&#xff0c;有资源背景的大V&#xff0c;也不是有运营团队的流量博主&#xff0c;而是从零开始&#xff0c;坚持不断写作的最普通创作者之一。 通过写作&#xff0c;他收入过万…

SpirngBoot整合快递100

目录 一、注册快递100 二、技术文档地址 三、需要认证的key和comcumer 四、spring boot 整合快递 100使用 4.1 引入快递100和hutool的依赖 4.2 将key和comcumer写入application.properties文件中 4.3 新建一个modle,用于将查出来的json数据转成对象 4.4 新建一个controll…

【yolov8】yolov8剪枝训练流程

yolov8剪枝训练流程 流程&#xff1a; 约束剪枝微调 一、正常训练 yolo train model./weights/yolov8s.pt datayolo_bvn.yaml epochs100 ampFalse projectprun nametrain二、约束训练 2.1 修改YOLOv8代码&#xff1a; ultralytics/yolo/engine/trainer.py 添加内容&#…

机器学习高频问答题总结

机器学习问答题总结 第一章 线性回归1.什么是线性回归&#xff1f;解释主要原理2.解释线性回归中最小二乘法的原理吗&#xff1f;3.如何评估线性回归模型的性能&#xff1f;4.线性回归中正则化的目的是什么吗&#xff1f;L1正则化和L2正则化有什么不同&#xff1f; 第二章 逻辑…

深入解析yolov5,为什么算法都是基于yolov5做改进的?(一)

YOLOv5简介 YOLOv5是一种单阶段目标检测算法&#xff0c;它在YOLOv4的基础上引入了多项改进&#xff0c;显著提升了检测的速度和精度。YOLOv5的设计哲学是简洁高效&#xff0c;它有四个版本&#xff1a;YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x&#xff0c;分别对应不同的模型大小…

神经网络与深度学习--网络优化与正则化

文章目录 前言一、网络优化1.1网络结构多样性1.2高维变量的非凸优化1.鞍点2.平坦最小值3.局部最小解的等价性 1.3.改善方法 二、优化算法2.1小批量梯度下降法&#xff08;Min-Batch&#xff09;2.2批量大小选择2.3学习率调整1.学习率衰减&#xff08;学习率退火&#xff09;分段…

MouseBoost PRO for Mac激活版:强大的 鼠标增强软件

在追求高效工作的今天&#xff0c;MouseBoost PRO for Mac成为了许多Mac用户的得力助手。这款功能强大的鼠标增强软件&#xff0c;以其独特的智能化功能和丰富的实用工具&#xff0c;让您的电脑操作更加便捷、高效。 MouseBoost PRO for Macv3.4.0中文激活版下载 MouseBoost PR…