第十八讲:联合和枚举

第十八讲:联合和枚举

  • 1.联合体(共用体)
    • 1.1联合体的声明
    • 1.2联合体大小的计算
    • 1.3联合体的特点
    • 1.4联合体的使用
      • 1.4.1联合体的直接使用
      • 1.4.2联合体直接使用的优化方法
      • 1.4.3联合体成员中含有数组的使用
      • 1.4.4使用联合体判断当前机器是大端排序,还是小端排序
    • 1.5联合体的具体使用例子
  • 2.枚举类型
    • 2.1枚举类型的声明
    • 2.2枚举成员值的讨论
      • 2.2.1原顺序
      • 2.2.2自己进行赋值
    • 2.3枚举的优点
    • 2.4枚举类型的使用
      • 2.4.1使用1
      • 2.4.2使用2

1.联合体(共用体)

1.1联合体的声明

联合体和结构体相似,联合体也是由一个或多个成员构成,这些成员可以是不同的类型,但是与结构体不同的是,联合体只为最大的成员分配足够的内存空间,而联合体的成员公用同一块内存空间,所以联合体也叫共用体,联合体的声明如下:

//1.1联合体的声明
//联合体的声明与结构体类似
union Book
{char name[10];int id;
};int main()
{//联合体变量的定义union Book b1 = { 0 };return 0;
}

1.2联合体大小的计算

对于下面的一串代码,联合体变量b1的大小是多少,为什么:

union Book
{char name;int id;
};int main()
{//联合体变量的定义union Book b1 = { 0 };//联合体变量的大小printf("%zd\n", sizeof(b1));return 0;
}

b1的大小为4,这就是因为:

1.联合体的大小至少是最大成员的大小
2.当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

例如:

//计算联合体的大小
union Un1
{char c[5];//对齐数:1//占五个字节int i;//对齐数:4//占4个字节//所以最大为5个字节,不是4的整数倍,补齐,解果为8
};
union Un2
{short c[7];//14个字节int i;//4个字节//一共为14个字节,不是4的倍数,补齐为16
};
int main()
{printf("%zd\n", sizeof(union Un1));//8printf("%zd\n", sizeof(union Un2));//16return 0;
}

1.3联合体的特点

既然联合体的成员共用同一块内存空间,那我们不妨来分析一下:

//联合类型的声明
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;
}

它们的结果为:
在这里插入图片描述
它们的地址是相同的,所以它们指向同一块内存空间的地址,那既然指向同一块空间的地址,对于其中的一个成员进行赋值,其他成员会受到影响吗:

//联合类型的声明
union Un
{char c;int i;
};
int main()
{//联合变量的定义union Un un = { 0 };un.i = 0x11223344;//先给i赋值,内存中存储的是:44332211(小端排序)un.c = 0x55;//给c赋值,此时内存中存储的是:55332211,显然会影响i的值1printf("%x\n", un.i);//i在内存中的存储被改变为:55332211,所以输出的结果为11223355return 0;
}

我们可以画图来理解:
在这里插入图片描述

1.4联合体的使用

1.4.1联合体的直接使用

//1.4.1联合体的直接使用
union Score
{int score1;int score2;
};int main()
{//因为score1和score2占用同一块内存空间,所以在使用时尽量一个一个进行使用:union Score s1;s1.score1 = 20;//使用score1...(例如:进行打印)printf("%d\n", s1.score1);//使用完s1之后,在使用s2:s1.score2 = 30;//使用score2...(例如:进行打印)printf("%d\n", s1.score2);//这样才能正确使用score1和score2,否则在使用score1时对score2进行操作很可能改变score1的值return 0;
}

1.4.2联合体直接使用的优化方法

上面的代码中,如果想要在一定时间内多次使用多种成员时,无法实现,所以我们探讨解决方法:

//1.4.2联合体直接使用的优化方法
union Score
{int score1;int score2;
};int main()
{union Score s1;s1.score1 = 20;//可以先创建一个保存score1值的变量int pscore1 = s1.score1;//这时我们就可以使用score2了:s1.score2 = 30;//再创建一个保存score2值的变量int pscore2 = s1.score2;//这时想要使用score1,就要将pscore1的值再传给score1:s1.score1 = pscore1;//使用score1...(例如:进行打印)printf("%d\n", s1.score1);return 0;
}

1.4.3联合体成员中含有数组的使用

当联合体成员中包含数组时,情况就有所不同:
在这里插入图片描述

如果我们这样进行赋值的话,可以看到它报错了,正确的使用方法如下:

  1. 使用strcpy函数
union Book
{char name[20];int price;
};int main()
{union Book b1;//先确定书的价钱b1.price = 20;//再确定书的名字//先对结构体进行清空memset(&b1, 0, sizeof(b1));//再使用strcpy函数进行赋值strcpy(b1.name, "tangjiasnashao");return 0;
}
  1. 使用循环
union Book
{char name[20];int price;
};int main()
{union Book b1;//先确定书的价钱b1.price = 20;//再确定书的名字memset(&b1, 0, 20);const char arr[20] = "tangjiasnashao";for (int i = 0; i < strlen(arr); i++)b1.name[i] = arr[i];return 0;
}
  1. 使用标准I/O函数
union Book
{char name[20];int price;
};int main()
{union Book b1;//先确定书的价钱b1.price = 20;//再确定书的名字memset(&b1, 0, 20);scanf("%s", b1.name);return 0;
}

使用fegts函数时换行符也会被存储,需要额外处理:

union Book
{char name[20];int price;
};int main()
{union Book b1;//先确定书的价钱b1.price = 20;//再确定书的名字memset(&b1, 0, 20);fgets(b1.name, 10, stdin);return 0;
}

1.4.4使用联合体判断当前机器是大端排序,还是小端排序

//1.4.4使用联合体判断当前机器是大端排序,还是小端排序
union Test
{char a;int b;
};int main()
{union Test t1;t1.b = 1;if (t1.a == 0)printf("大端排序\n");if(t1.a == 1)printf("小端排序\n");return 0;
}

1.5联合体的具体使用例子

看到联合体的使用如此繁琐,我们是不是感觉:还没有结构体好用,那么就让我们看一下联合体的具体使用:

⽐如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。
每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息:
在这里插入图片描述
我们对它们进行分析:

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

2.枚举类型

2.1枚举类型的声明

枚举其实就是⼀⼀列举

比如:

1.⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
2.性别有:男、⼥、保密,也可以⼀⼀列举
3.⽉份有12个⽉,也可以⼀⼀列举
4.三原⾊,也是可以⼀⼀列举

这些数据的表示就可以使用枚举:

//枚举的声明
enum Day //星期
{Mon, //每个成员后边需要加逗号Tues,Wed,Thur,Fri,Sat,Sun //最后一个成员后边不用加逗号
};enum Sex//性别
{MALE,FEMALE,SECRET
};enum Color//颜⾊
{RED,GREEN,BLUE
};

2.2枚举成员值的讨论

对于枚举成员,它们其实是有值的,我们现在对它们的值进行讨论:

2.2.1原顺序

//2.2.1原顺序
enum Day //星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};int main()
{printf("%d\n", Mon); //0printf("%d\n", Tues); //1printf("%d\n", Wed); //2printf("%d\n", Thur);//3printf("%d\n", Fri); //4printf("%d\n", Sat); //5printf("%d\n", Sun); //6return 0;
}

可见它们的值是从0开始,往后加的

如果我们想要自己给枚举成员赋值,也是可行的,但是只能在创建枚举类型时进行赋值,不能在main函数或其他函数中进行更改

2.2.2自己进行赋值

//2.2.2情况1
enum Day //星期
{Mon,Tues,Wed = 7,Thur,Fri,Sat,Sun
};int main()
{printf("%d\n", Mon); //0printf("%d\n", Tues); //1printf("%d\n", Wed); //7printf("%d\n", Thur);//8printf("%d\n", Fri); //9printf("%d\n", Sat); //10printf("%d\n", Sun); //11return 0;
}

2.3枚举的优点

当然我们可以使用define定义常量,那为什么要使用枚举呢

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较,枚举有类型检查,更加严谨。
  3. 便于调试,预处理阶段会删除 #define 定义的符号
  4. 使⽤⽅便,⼀次可以定义多个常量
  5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

2.4枚举类型的使用

2.4.1使用1

enum Color//颜⾊
{RED=1,GREEN=2,BLUE=4
};int main()
{enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值//后续可以通过这个值进行判断,比如:if (clr == 	GREEN)printf("YES");return 0;
}

2.4.2使用2

比如当我们想要写一个简单的计算器时,会这样写:

int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这样写可读性低,此时我们可以使用枚举:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

K8s(Kubernetes)常用命令

大家好&#xff0c;当谈及容器编排工具时&#xff0c;Kubernetes&#xff08;常简称为K8s&#xff09;无疑是当今最受欢迎和广泛使用的解决方案之一。作为一个开源的容器编排平台&#xff0c;Kubernetes 提供了丰富的功能&#xff0c;可以帮助开发人员和运维团队管理、部署和扩…

电商分析@电商数据与运营优化

电商数据分析与运营优化是指通过对电商平台的各种数据进行深入分析&#xff0c;以发现潜在的问题和机会&#xff0c;并采取相应的优化措施&#xff0c;提高电商运营效率和盈利能力。 首先&#xff0c;电商数据分析需要收集和整理各类数据&#xff0c;包括销售数据、用户数据、流…

大宋咨询(深圳车主满意度调查)如何开展汽车展会观众满意度问卷调查

汽车展览是由政府机构、专业协会或主流媒体等组织,在专业展馆或会场中心进行的汽车产品展示展销会或汽车行业经贸交易会、博览会等活动。汽车展览通过对汽车工艺的呈现与汽车产品的广告,为消费者提供汽车制造工业与汽车产品的发展动向。同时,汽车厂商可通过汽车展览对外宣传产品…

实战16:基于apriori关联挖掘FP-growth算法挖掘关联规则的手机销售分析-代码+数据

直接看视频演示: 基于apriori关联挖掘关联规则的手机销售分析与优化策略 直接看结果: 这是数据展示: 挖掘结果展示: 数据分析展示:

利用WK2168实现串口服务器

ESP32 SPI与WK2168实现串口服务器 概述系统组成代码概述 一些老设备通过RS485采集数据,如果在一个系统中采用几个RS485设备可能是一个不错的选择,但要是使用46个RS485数据采集设备为一个PLC提供外部数据,系统的性能就很难有保障了。通过一个串口服务器实现看来是一个好的选…

智慧校园有哪些特征

随着科技的飞速进步&#xff0c;教育领域正经历着一场深刻的变革。智慧校园&#xff0c;作为这场变革的前沿代表&#xff0c;正在逐步重塑我们的教育理念和实践方式。它不仅仅是一个概念&#xff0c;而是一个集成了物联网、大数据、人工智能等先进技术的综合生态系统&#xff0…

SpringBoot源码(自动装配、内嵌Tomcat)

文章目录 依赖管理pom依赖管理Web依赖自定义starter 一、WebMvcAutoConfiguration1.1 Filter1.2 Interceptor 二、源码解析2.1 SpringApplication2.1.1 构造方法1、填充webApplicationType2、自动装配Initializers3、自动装配Listeners 2.1.2 run(args) 2.2 SpringApplicationR…

手写Mitt实现事件订阅、发布和取消订阅

Mitt类设计 emitter属性&#xff1a;用于存储事件和对应的处理器 on方法&#xff1a;订阅事件 off方法&#xff1a;取消订阅事件 emit方法&#xff1a;触发事件 export class Mitt<T> {private readonly emitter: Record<string, Array<(value: T[keyof T]) …

AI边缘计算盒子在智慧交通的应用

方案背景 随着经济增长&#xff0c;交通出行需求大幅增长&#xff0c;但道路建设增长缓慢&#xff0c;交通供需矛盾日益显著&#xff0c;中心城区主要道路高峰时段交通拥堵严重&#xff0c;道路交通拥堵逐渐常态化&#xff0c;成为制约城市可持续发展的重要因素之一。 痛点问题…

web 前端开发技术---网页的制作

这是一个网页代码 上年包含了电子邮件&#xff0c;选项建 等等 分享给大家 <!-- prj_7_1.html --> <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8"><title>留言板设计</title><style type&…

【C++】入门(一):命名空间、缺省参数、函数重载

目录 一、关键字 二、命名空间 问题引入(问题代码)&#xff1a; 域的问题 1.::域作用限定符 的 用法&#xff1a; 2.域的分类 3.编译器的搜索原则 命名空间的定义 命名空间的使用 举个&#x1f330;栗子&#xff1a; 1.作用域限定符指定命名空间名称 2. using 引入…

【数据结构与算法 | 堆篇】JAVA实现小顶堆

1. 堆的特点 堆的逻辑结构是数组&#xff0c;内存结构是完全二叉树.完全二叉树即只有最后一层才有叶子节点.堆又分为大顶堆与小顶堆. 大顶堆的特点是 : 父亲节点比孩子节点的都要大. 小顶堆的特点与其相反.Java的优先级队列(PriorityQueue)的底层实现即用到了小顶堆. 所以下文…

K210视觉识别模块学习笔记3:内存卡写入拍摄图片_LED三色灯的操作_按键操作_定时器的配置使用

今日开始学习K210视觉识别模块: LED三色灯的操作_按键操作_定时器的配置使用_内存卡写入拍摄图片 亚博智能的K210视觉识别模块...... 本文最终目的是编写一个按键拍照的例程序&#xff1a; 为以后的专用场景的模型训练做准备&#xff0c;因为训练自己的模型需要大量的图片&a…

jmeter基础入门练习题

jmeter存在A,B两个线程组的情况下&#xff0c;默认设置下&#xff0c;运行顺序是&#xff1a;A A&#xff1a;A,B同时运行 B&#xff1a;先运行A&#xff0c;在运行B C&#xff1a;先运行A&#xff0c;等待2s运行B D:先A运行完&#xff0c;等待默认设置时间后运行B 下列说法正…

编译安装PHP服务(LAMP3)

目录 1.初始化设置&#xff0c;将安装PHP所需软件包传到/opt目录下 &#xff08;1&#xff09;关闭防火墙 &#xff08;2&#xff09;上传软件包到/opt目录 2.安装GD库和GD库关联程序&#xff0c;用来处理和生成图片 3.配置软件模块 4.编译及安装 5.优化把PHP 的可执行程…

nginx的安装001

Nginx是一款高性能的HTTP和反向代理服务器&#xff0c;以及邮件代理服务器&#xff0c;由 Igor Sysoev 开发并公开发布于2004年。Nginx以其高并发处理能力、低内存消耗和稳定性著称&#xff0c;特别适合部署在高流量的网站上。 操作系统&#xff1a; CentOS Stream 9 安装步骤…

【算法训练 day44 分割等和子集】

目录 一、分割等和子集-LeetCode 416思路实现代码1.二维dp代码2.一维dp代码 问题总结 一、分割等和子集-LeetCode 416 Leecode链接: leetcode 416 文章链接: 代码随想录 视频链接: B站 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&…

SQL入门教程,很详细

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理关系数据库的标准语言。它被广泛用于存储、操作和检索数据。在这篇文章中&#xff0c;我们将介绍SQL的基本概念和常用命令。 首先&#xff0c;我们需要了解SQL的基本结构。SQL语句通常由以下几个部分组成&…

头歌数据结构与算法课程设计易-算式运算的合法性

给定一个算式运算&#xff0c;算式由运算数、、-、、/、(、)组成&#xff0c;请编写程序判断该算式运算是否合法。如果合法&#xff0c;计算该算式的值。 输入描述&#xff1a; 第一行输入一个运算表达式 输出描述&#xff1a; 如果表达式合法则计算其值&#xff0c;结果保留两…

c语言之向文件读写数据块

c语言需要向文件读写数据块需要用到fread语句和fwrite语句 fread语句的语法格式 fread(butter,size,count,fp) butter&#xff1a;读取的数据存入内存地址 size:读取的字节大小 count:读取数据的个数 fp:读取的文件指针 fwrite语句语法格式 fwrite(butter,size,count,fp…