C语言 联合和枚举

目录

  • 1. 联合体
    • 1.1 联合体类型的声明
    • 1.2 联合体变量的创建
    • 1.3 联合体的特点
    • 1.4 联合体在内存中的存储
    • 1.5 联合体使用举例
  • 2. 枚举类型
    • 2.1 枚举类型的声明
    • 2.2 枚举变量的创建和初始化
    • 2.3 枚举类型的大小
    • 2.4 枚举类型的优点


正文开始

上次我们通过《C语言 结构体详解》学习了结构体的相关知识,今天我们来学习一下结构体的亲戚联合枚举,它们同结构体一样,都是C语言中的自定义类型,由一个或多个成员构成。因为本文所讲内容与结构体有很多相似之处,所以先学习结构体再食用本文更佳呦~

1. 联合体

1.1 联合体类型的声明

联合体的声明和结构体的声明类似:

union Un_name
{member-list;
};

其中:

  • union用来声明这是一个联合体
  • Un_name是联合体名
  • member-list为成员列表

1.2 联合体变量的创建

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

联合体变量的创建以及初始化等与结构体基本相同,这里不再赘述。

1.3 联合体的特点

联合体的声明与结构体基本相同,那两者有什么区别呢?我们都知道结构体在内存中的存储符合内存对齐规则,这样做的好处就是增强了性能,但是却浪费了空间。而联合体主打一个节省空间,原因如下:

  • 联合体成员共用一块内存(所以联合体又叫共用体)
  • 联合体大小至少为最大成员的大小,这样才能确保能放下所有数据

我们写个代码验证一下:

# include <stdio.h>union Un
{char c;int i;
};int main()
{union Un un = { 0 };printf("%p\n", &(un.c));printf("%p\n", &(un.i));printf("%p\n", &un);return 0;
}

运行结果:
在这里插入图片描述
由此我们验证了,联合体成员共用一块内存。

1.4 联合体在内存中的存储

联合体成员共用一块内存,那他们究竟是怎么存储的呢?

  • 联合体的大小至少是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
  • 由于联合体成员共用同一块内存,所以一般独立使用各个联合体成员

例如:

#include <stdio.h>union Un1
{char c[5];int i;
};union Un2
{short c[7];int i;
};int main()
{printf("Un1 -> %zd\n", sizeof(union Un1));printf("Un2 -> %zd\n", sizeof(union Un2));return 0;
}

在内存中的存储情况如下:
在这里插入图片描述

上图可以看出,整个联合体的大小满足两个条件:

  • 至少是最大成员的大小
  • 大小要对齐到最大对齐数的整数倍。例如 Un1 最大的对齐数是4,所以总大小补齐为8;Un2 最大的对齐数是4,所以总大小补齐为16

运行验证一下:
在这里插入图片描述

1.5 联合体使用举例

假如我们需要记录图书、杯子、衬衫三种商品的数据,每一种商品都有:库存量、价格、商品类型和一些其他信息:

  • 图书:书名、作者、页数
  • 杯子:设计
  • 衬衫:设计、颜色、尺寸

如果我们使用结构体书写:

struct Product
{//共有属性int stock_number;//库存量double price;//价格int item_type;//商品类型//特有属性char title[20];//书名char author[20];//作者int num_page;//页数char design[30];//设计int colors;//颜色int sizes;//尺寸
};

这样写似乎没有什么问题,但一个结构中包含了所有商品的各种属性,当我们描述图书的时候,就用不上设计、颜色和设计,这样就使得结构体的大小偏大,比较浪费内存。所以我们可以使用联合体书写:

struct Product
{//共有属性int stock_number;//库存量double price;//价格int item_type;//商品类型union{struct{char title[20];//书名char author[20];//作者int num_page;//页数}book;//图书struct{char design[30];//设计}mug;//杯子struct{char design[30];//设计int colors;//颜色int sizes;//尺寸}shirt;//衬衫}item;
};

这样就相当于把三种商品的特有属性共存在一块内存中,使用时也相互独立,这样保证了正常使用,也能够节省空间。

2. 枚举类型

枚举,顾名思义就是一个一个列举,比如我们现实生活中:

  • 星期一到定期日可以列举
  • 性别可以列举
  • 月份可以列举

2.1 枚举类型的声明

枚举类型的声明与结构体类似:

enum Enum_name
{value1,value2,value3,//...
};
  • 使用关键字enum来声明枚举类型
  • Enum_name为枚举名
  • {}中的内容为枚举类型的可能取值,称作枚举常量。
  • 枚举常量之间由,隔开
  • 枚举常量都是有初始值的,默认从0开始,步长为1依次递增。
  • 给定枚举常量的值,就类似于#define定义标识符,只不过#define是在预处理阶段完成的,枚举类型是在编译阶段完成的

例如:

enum Color
{RED,//0GREEN,//1BLUE//2
};

我们也在声明枚举类型时赋值:

enum Color1
{RED=3,//3GREEN,//4BLUE//5
};enum Color2
{RED=3,//3GREEN=5,//5BLUE=7//7
};enum Color3
{RED,//0GREEN=3,//3BLUE//4
};

对于枚举类型的理解:
声明一个枚举,就是定义了一种类型,这种类型的可能取值就是枚举常量的值

2.2 枚举变量的创建和初始化

枚举变量的创建和初始化与结构体类似,这里只做演示,详情不再赘述。

enum Color
{RED,//0GREEN,//1BLUE//2
};int main()
{enum Color red = 0;//等同于RED//定义了一个类型为 enum Color 的枚举变量red//变量 red 的值为0,也就是REDreturn 0;
}

2.3 枚举类型的大小

枚举是一种数据类型,它的可能取值就使枚举常量的值,枚举常量本质都是整型,也就是说,不管是枚举类型,还是枚举变量,亦或是枚举常量,它们的大小都与整型相同,都是4个字节,下面我们验证一下:

#include <stdio.h>enum Color
{RED,GREEN,BLUE
};int main()
{enum Color red;printf("%d\n", sizeof(enum Color));//枚举类型printf("%d\n", sizeof(RED));//枚举常量printf("%d\n", sizeof(GREEN));//枚举常量printf("%d\n", sizeof(BLUE));//枚举常量printf("%d\n", sizeof(red));//枚举变量return 0;
}

运行结果:
在这里插入图片描述

2.4 枚举类型的优点

有的人可能会想到,既然都是定义常量,那为什么不用#define呢?

因为枚举有以下优点:

  • 枚举将标识符集中起来,不像是#define那样分散开,增加了代码的可读性和可维护性
  • 枚举类型定义的标识符有类型检查(是枚举类型),更为严谨,而#define没有(直接替换)
  • 便与调试,预处理阶段会删除#define定义的符号
  • 使用方便,一次可以定义多个常量
  • 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用,而#define定义的标识符是全部都直接替换


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

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

相关文章

C语言 | Leetcode C语言题解之第66题加一

题目&#xff1a; 题解&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* plusOne(int* digits, int digitsSize, int* returnSize){for(int i digitsSize - 1; i > 0; --i){digits[i] digits[i] 1;//最后元素1判断是不…

笔试狂刷--Day12(模拟 + 链表的公共节点 + dp)

大家好,我是LvZi,今天带来笔试狂刷--Day12(模拟 链表的公共节点 dp) 一.删除公共字符&#xff08;哈希&#xff09; 题目链接:删除公共字符&#xff08;哈希&#xff09; 分析: 分别读取俩个字符串,将第二个字符串存储到set之中,再遍历第一个字符串,删除公共字符 代码: …

《网络安全技术 网络安全众测服务要求》

近日&#xff0c;全国网络安全标准化技术委员会发布《网络安全技术 网络安全众测服务要求》&#xff08;GB/T 43741-2024&#xff0c;以下简称“众测服务要求”&#xff09;&#xff0c;并将在2024年11月1日正式实施。 《众测服务要求》确立了网络安全众测服务的角色及其职责&…

ruoyi漏洞总结

若依识别 黑若依 :icon hash"-1231872293 绿若依 :icon hash"706913071” body" 请通过前端地址访 " body" 认证失败&#xff0c;无法访问系统资源 " 如果页面访问显示不正常&#xff0c;可添加默认访问路径尝试是否显示正常 /login?redi…

Dashboard 介绍

Dashboard 介绍 一、K8S Dashboard简介 简单的说&#xff0c;K8S Dashboard是官方的一个基于WEB的用户界面&#xff0c;专门用来管理K8S集群&#xff0c;并可展示集群的状态。K8S集群安装好后默认没有包含Dashboard&#xff0c;我们需要额外创建它 二、RABC简介 还是那句话&a…

MLP手写数字识别(1)-MNIST数据集下载与可视化(tensorflow)

1.下载与查看MNIST数据集 from keras.datasets import mnist(x_train_image,y_train_label),(x_test_image,y_test_label) mnist.load_data() print("train images:",x_train_image.shape) print("test images:",x_test_image.shape) print("train …

LeetCode 面试经典150题 28.找出字符串中第一个匹配项的下标

题目&#xff1a;给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 思路&#xff1a;暴力&#xff08;…

RabbitMQ知识点总结和复习

之前项目中用到RabbitMQ的场景主要是订单信息的传递&#xff0c;还有就是利用RabbitMQ的死信队列属性设置&#xff0c;实现延迟队列效果&#xff0c;实现超时支付取消功能&#xff0c;以及在两个不同项目中传递数据等场景。 最近几年的工作中都是一直用的RabbitMQ&#xff0c;…

Springboot+MybatisPlus入门案例(postman测试)

一、项目框架 pom.xml依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apac…

基于php+mysql+html图书管理系统(含实训报告)

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

任何内核都无法启动解决方案

背景 实验中不停编译新的内核又懒得删除了&#xff0c;于是乎在编译到第9716个内核后&#xff0c;无法启动了。 报错如下&#xff1a; 主要是这句报错&#xff1a; 解决方案 ubuntu linux开机进入不了系统的解决办法 进入Recovery Mode打开root shell失败&#xff1a; 一…

【数据结构】您有一份KMP算法教学已到账,请注意查收!!!

KMP算法 导读一、KMP算法1.1 重要术语1.2 部分匹配值1.3 部分匹配值的作用 二、KMP算法原理2.1 从指针的角度理解KMP算法2.2 从匹配的角度理解KMP算法2.3 小结 三、KMP算法的实现3.1 next数组3.2 next数组的计算3.2.1 通过PM值计算next数组3.2.2 通过移位模拟计算next数组3.2.3…

基于Spring Boot的音乐网站与分享平台设计与实现

基于Spring Boot的音乐网站与分享平台设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 系统功能界面图&#xff0c;在系统首页可以查看首…

【软件工程】详细设计

目录 前言详细设计算法设计工具——判定表 前言 软件工程生命周期分为八个阶段&#xff1a; 问题定义—>可行性研究—>需求分析 —>概要设计—>详细设计—>编码与单元测试 —>综合测试—>软件维护 这节我们讲的是软件开发流程中的一个阶段&#xff0c;需求…

✔ ★Java大项目——用Java模拟RabbitMQ实现一个消息队列(二)【创建核心类、封装数据库操作】

✔ ★Java大项目——用Java模拟RabbitMQ实现一个消息队列 四. 项⽬创建五. 创建核⼼类 ★创建 Exchange&#xff08;名字、类型、持久化、自动删除、参数&#xff09;创建 MSGQueue&#xff08;名字、持久化、独占标识&#xff09;创建 Binding&#xff08;交换机名字、队列名字…

OpenCV(四)—— 车牌号识别

本节是车牌识别的最后一部分 —— 车牌字符识别&#xff0c;从一个完整的车牌图片到识别出车牌上的字符大致需要如下几步&#xff1a; 预处理&#xff1a;将车牌图片灰度化、二值化&#xff0c;并去除识别时的干扰因素&#xff0c;比如车牌铆钉字符分割&#xff1a;将整个车牌…

Linux——命名管道

管道特点 只能用于具有具体祖先的进程之间的通信&#xff0c;通常&#xff0c;一个管道由一个进程创建&#xff0c;然后该进程调用fork&#xff0c;创建子进程&#xff0c;关闭相应的读写端&#xff0c;然后父子进程就可以通信了管道提供流式服务一般而言&#xff0c;进程退出…

一个肉夹馍思考的零耦合设计

刷抖音听说知识付费是普通人的一个收入增长点&#xff0c;写了三十几篇文章一毛钱没赚&#xff0c;感觉有点沮丧。天上下着小雨雨&#xff0c;稀稀嗦嗦的&#xff0c;由于了很久还是买了一个&#x1f928;。 忽然觉得生活有点悲催&#xff0c;现在已经变得斤斤计较&#xff0c;…

Modelsim自动仿真平台的搭建

Modelsim自动仿真平台的搭建 如果要搭建自动仿真平台脚本那就需要更改下面3个文件。run_simulation.bat、complie.do和wave.do文件。注&#xff1a;前提是安装了modulsim并且配置好了环境变量&#xff0c;这里不过多介绍。 一、下面是run_simulation.bat文件的内容 : 注释的…

四足机器人摆线规划程序

一、标准摆线公式 { x r ∗ ( θ − sin ⁡ ( θ ) ) y r ∗ ( 1 − cos ⁡ ( θ ) ) \left\{\begin{array}{l} xr *(\theta-\sin (\theta)) \\ yr *(1-\cos (\theta)) \end{array}\right. {xr∗(θ−sin(θ))yr∗(1−cos(θ))​ 这里的r表示摆线的圆的半径&#xff0c; θ \…