C语言自定义类型-联合与枚举

在之前的文章中,我们学到了结构体类型,而结构体其实归属于一个大类——自定义类型。那么今天我们就继续讲解关于自定义类型的知识~

一、类型命名关键字-typedef

typedef的作用其实就是标题的意思——为一种类型赋予新的名字。

① typedef在变量中的应用

光靠说的或许并体现不出它的作用,我们举一个例子:比如我们平常在编程中,想使用较大的数字于是此时我们想要使用long long型的变量,但我们在定义变量时嫌弃long long类型名的名字太长,所以我们可以为long long取一个新的名字

typedef long long LL;
int main()
{LL a = 0;a = 99999999999999999;printf("a = %lld\n", a);return 0;
}

如此便能够使用"LL"两个简短的字母来代替long long啦~

② typedef在结构体中的应用

在结构体创建后,正常来说想要初始化一个结构体,我们需要使用结构体类型名去初始化,而当我们觉得此类型名过于长,或者需要定义的结构体过多,麻烦时就可以使用typedef来为结构体类型名起一个别名,用于使初始化变得便捷

struct Student {char name[20];char s;int num;
};
typedef struct Student s;
int main()
{s arr = { "abcdef",'A',10 };printf("%s %c %d", arr.name, arr.s, arr.num);return 0;
}

有结构体类型名:

typedef struct Student{char name[20];
}s;//结构体类型变量为:s

无结构体类型名:

typedef struct {char name[20];
}s;//结构体类型变量为:s

二、联合体

① 联合体类型声明与内存

联合体与结构体相似,联合体也是一个由多个成员变量所构成的,并且这些成员变量都可以是不同的类型。

union 联合体名
{数据类型 成员1;数据类型 成员2;...
};

联合体与结构体的区别是:结构体的内存是通过对齐数计算,并且最终内存必须是对齐数的整数倍。而对于联合体,编译器只为其最大成员分配足够内存空间(但联合体大小内存必须为所有成员变量内存的整数倍),所以联合体的特殊之处也就是"所有成员共用一块内存空间",所以联合体也叫做"共用体"。

union s 
{char name[12];int age;
};
int main()
{union s stu = { 0 };printf("%d", sizeof(stu));return 0;
}

我们可以看到,当我们计算联合体的大小时,大小为12的name和大小为4的age,但最终得到的大小仅仅为12,这就是因为两者共用一块空间并且如果当我们将char name[12]改成char name[10]时,会发现大小仍为12这是因为联合体大小必须为其成员变量大小的整数倍。

char name[12]和int age在内存中的存储方式为:

② 联合体的初始化

看到这里大家或许觉得,联合体能存储这么多变量,并且占的内存还不多~处处都比结构体强,简直是百利而无一害呀~但其实不是这样的 T A T,让我们继续往下看⬇

当我们创建完联合体,想要为联合体的成员变量进行初始化时,如果只初始化一个成员变量:

union s
{char name[12];int age;
};
int main()
{union s stu = {"hello world"};printf("name = %s\n", stu.name);return 0;
}

此时这种初始化是能够成功进行的,但如果我们想同时初始化两个成员变量:就会出现这种报错的情况。交换一下位置也是一样的情况,这是因为成员变量们所占用的空间是共同的,当对一个变量进行初始化后,想要再对另一个变量初始化,所改变的内存就会影响第一个变量的值。

这就是联合体的坏处,它虽然能够一定程度上节省内存,但是并无法同时使用多个变量。

并且,需要注意的是:每次只能对一个成员变量进行初始化,所以想要改变不是第一个的成员变量,就不能直接输入值,而是必须指定相应的变量进行赋值:

union s
{char name[12];int age;int time;
};
int main()
{union s stu = {.age = 18};printf("age = %d\n", stu.age);return 0;
}

当我们在定义过char name[12]后,再定义了其他的变量,就不能够再去使用name:

union s
{char name[12];int age;int time;
};
int main()
{union s stu = {"zhang san"};//未初始化其他变量时输出name:printf("name = %s\n", stu.name);stu.age = 18;printf("age = %d\n", stu.age);//初始化age后再输出name:printf("name = %s\n", stu.name);return 0;
}

因为当我们第一次初始化name时,此时联合体中的内存是这样的:但当我们又初始化int后,联合体中的内存就是这样了:

(在对联合体进行初始化时,是从低字节还是高字节开始改变取决于当前编译器是大端环境还是小端环境)

③ 联合体的实际应用

当知道联合体的使用条件如此苛刻,各位是不是又觉得,联合体就没有使用的必要了呢?其实也不尽然,毕竟联合体与结构体相比,确确实实的能够节省相当多的空间了,仅仅几个变量或许看不出来,但变量非常多,非常复杂,并且有重复时,就能够体现出联合体的作用了

比如此时我们要举办一个活动,上线三个新的产品:图书,衬衫,杯子。

而这三种商品除了共有的信息:"库存量","价格","商品标签"等,还有很多不共有的其他信息:

图书:书名,作者,页数
衬衫:设计,颜色,尺寸
被子:设计,材质

如果我们并不加以思考,直接使用结构体去进行创建变量:

struct commodity
{//共有信息:int number;//库存量double price;//价格int type;//商品标签//非共有信息:char name[20];//书名char writer[20];//作者int page;//页数char devise[30];//设计int color;//颜色int size;//尺寸int material;//材质
};

虽然是可以使用的,并且创建起来也简单,但是其中的缺点就是有很多不必要浪费的空间比如我们想使用图书时,就不需要:"设计","颜色","尺寸","材质"这四个因素。而想单独使用其他两种商品时也是同理。

此时我们就可以使用联合体来代替结构体,将公共的部分作为成员变量放进结构体,而三种商品分别独自拥有的属性就使用联合体分别分装,在使用某种商品时,就用到某种商品的元素,而不会导致出现过多的内存浪费:

struct Commodity
{//共有信息:int number;//库存量double price;//价格int type;//商品标签union {struct{char name[20];//书名char writer[20];//作者int page;//页数}Book;struct{char devise[30];//设计int color;//颜色int size;//尺寸}Shirt;struct{char devise[30];//设计int material;//材质}Cup;}choose;
};

再让我们看一下两种不同的方法,所占内存大小的差别:

三、枚举类型 

① 什么是枚举类型?

枚举类型能让你自定义随意的命名,创建有各种成员组成,它允许你为一组相关的常量赋予有意义的名字,以提高代码的可读性和可维护性。

那么枚举类型应该如何使用呢?其实就是将自己想要使用的常量进行列举~

比如我们上高中,理科生学习的科目就分别是:语文,数学,英语,物理,化学,生物,可以列举。

或者一个星期有七天:星期一,星期二,星期三,星期四,星期五,星期六,星期日,可以列举。

又或者一年有十二个月份,也可以一一列举。

② 枚举类型的定义

enum 枚举类型名 
{常量1,常量2,...
};

(需要注意的是,常量后接的是" , ",而并不是" ; ")

了解了枚举类型的定义形式,让我们使用上面的例子,试着定义几个枚举吧:

高中科目:

enum subjects
{Chinese,mathematics,English,physics,chemistry,creature
};

星期:

enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};

上面定义的subjects与Day都是枚举类型,并且其中所定义的成员也都是有值的如果并未进行初始化,那么从第一个成员开始,默认第一个为0,第二个为1,第三个为2...直到结束并且枚举类型也可以将其中的成员进行赋值,其后的成员按照该成员的值依次加1。

③ 枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

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

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

3. 便于调试,预处理阶段会删除 #define 定义的符号

4. 使用方便,一次可以定义多个常量

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

④ 枚举类型的使用

我们可以使用枚举类型创建很多成员,并且为其赋值,然后使用枚举变量作为函数的参数。比如我们可以创建一个星期表,创建一个枚举类型存储星期一到星期七,通过我们输入的值,进入函数中判断枚举类型中的哪个变量,再进行打印。

enum Day
{Mon = 1, Tues, Wed, Thur, Fri, Sat, Sun
};
void printDay(enum Day day)
{switch (day){case Mon:printf("星期一\n");break;case Tues:printf("星期二\n");break;case Wed:printf("星期三\n");break;case Thur:printf("星期四\n");break;case Fri:printf("星期五\n");break;case Sat:printf("星期六\n");break;case Sun:printf("星期日\n");break;}
}
int main()
{enum Day num;printf("请输入1-7\n");scanf("%d", &num);printDay(num);return 0;
}

那么关于C语言的自定义类型相关知识就为大家讲解到这里啦,如果有哪里讲的不够清楚,或者有出错的地方,还请大家多多在评论区指出,我也会吸取教训,多多改正的!那么我们下期再见啦~

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

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

相关文章

Java【集合】

一、集合的概述 集合建立在数组基础上,主要位于java.util包中,用来存储Java类对象,并且可以实现各种数据结构。 集合大小可以改变,可以存放不同数据类型数据。集合不能存放基本类型数据,只能存放引用数据类型数据。集…

力扣题解2848

大家好,欢迎来到无限大的频道。 今日继续给大家带来力扣题解。 题目描述(简单): 与车相交的点 给你一个下标从 0 开始的二维整数数组 nums 表示汽车停放在数轴上的坐标。对于任意下标 i,nums[i] [starti, endi] &…

中考全国45套(全国教育发达地区中考试卷)

文章目录 获取方式 为什么选择这份资源? 权威性与全面性:我们精心搜集了全国教育发达地区的最新中考试卷,确保每一套试卷都代表了该地区的教学水平和考试趋势。这不仅涵盖了丰富的知识点,还融入了各地独特的命题风格,让…

2020ICPC上海 D - Walker M - Gitignore

D: 首先显然要二分,判断当前二分的mid时间下是否能满足走满0~n 枚举所有情况,这里按照左,右起点p1,p2分别讨论 p1向左 p2向左(以下向左和向右都代表向左或者向右到墙,而不代表初速度方向),只需要计算p1或者p2反弹之后还能走距离n就是合法 p1向左 p2向右&#xff…

3.4.2 __ipipe_init_early之fixup_percpu_data()

点击查看系列文章 》 Interrupt Pipeline系列文章大纲-CSDN博客 3.4.2 __ipipe_init_early之fixup_percpu_data() 这个函数只有在CPU是SMP对称多core的情况下,才会真正运作,否则就是个空函数。 #ifdef CONFIG_SMPstatic inline void fixup_percpu_data…

H5 three.js 实现六年级观察物体

o(&#xffe3;▽&#xffe3;)ブ 我又带着新的demo来啦~ 预览 功能点 立方体的阴影 立方体的添加 位置记录 最大限制 三视图展示 立方体的移除 答题模式 随机出题 题库出题 源码 注释算是比较全了&#xff0c;可能部分会有点绕&#xff0c;还能够再优化一下~ <!DOCTYPE …

【代码随想录训练营第42期 续Day58打卡 - 图论Part8 - Dijkstra算法

目录 一、Dijkstra算法 实现方式 1、使用优先队列&#xff08;最小堆&#xff09; 2、朴素法&#xff08;简单数组&#xff09; 二、经典例题 题目&#xff1a;卡码网 47. 参加科学大会 题目链接 题解&#xff1a;朴素Dijkstra 三、小结 一、Dijkstra算法 刚入门Dijks…

AI论文写作测评!类似茅茅虫论文写作助手网站

在当前的学术研究和写作环境中&#xff0c;AI论文写作助手成为了许多学者和学生的重要工具。其中&#xff0c;千笔-AIPassPaper和茅茅虫论文写作助手是两款备受关注的平台。本文将对这两款工具进行详细测评&#xff0c;并推荐适合不同需求的用户使用。 千笔-AIPassPaper AI论文…

实现领域驱动设计(DDD)系列详解:限界上下文

随着微服务的兴起&#xff0c;限界上下文更是被拔高到战略设计的核心地位&#xff0c;也成了连接问题空间与解空间的重要桥梁&#xff0c;但不可否认&#xff0c;一方面&#xff0c;领域驱动设计社区纷纷发声强调它的重要性&#xff1b;另一方面&#xff0c;还有很多人依旧弄不…

游戏算法专题之PRD算法:听说你想凭运气抽中荣耀水晶?

PRD算法全称Pseudo-Random Distribution。是概率分布中的一种常见算法&#xff0c;在游戏开发领域中很常用。 PRD用于控制随机事件的触发概率&#xff0c;使其表现得更加符合预期&#xff0c;相比于传统得随机数生成&#xff0c;PRD算法可以平滑得控制随机事件的触发次数&…

计算机毕业设计 二手闲置交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

什么是快充协议,最常见的快充协议有哪些

什么是快充协议 随着手机快充的出现大家都知道快充技术但很多人确不知道快充协议&#xff0c;在快充技术里快充协议是必不可少的&#xff0c;那么今天我们就来探讨一下什么是快充协议&#xff1f; 快充协议是一种通过提高充电效率来缩短设备充电时间的电池充电技术。它通过在充…

主播和礼品检测系统源码分享

主播和礼品检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

约瑟夫环和一元多项式修正版

这里先附上上一篇博文的链接大家可以对比着看&#xff0c;错误已经改正https://blog.csdn.net/2302_78946488/article/details/141751514?spm1001.2014.3001.5501 约瑟夫环 以下是详细代码 //约瑟夫环 #include<stdio.h> #include<stdlib.h> //建立链表结点 str…

【Unity】 HTFramework框架(五十六)MarkdownText:支持运行时解析并显示Markdown文本

更新日期&#xff1a;2024年9月15日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 MarkdownText支持的Markdown语法标题强调文本表格嵌入图像超链接 使用MarkdownText设置项运行时属性解析使用ID模式嵌入图像 MarkdownText MarkdownText…

句子成分——每日一划(八)

目录 一、原句 二、第一部分 三、第二部分 一、原句 In class society everyone lives as a member of a particular class, and every kind of thinking, without exception, is stamped with the brand of a class. 来源&#xff1a;二、阶级和阶级斗争 二、第一部分 In…

QT添加图标标题和打包项目

QT项目打包 项目的标题和图标标题项目图标exe图标 可执行文件——生成exeexe运行报错“找不到qt6gui.dll”等 相关库文件——生成zip安装包打包程序——生成exe安装包 项目的标题和图标 项目打包要好看点&#xff0c;得有个好点的标题和图标&#xff0c;这次打包的项目是我上一…

图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲

拓扑排序 题目链接&#xff1a;117. 软件构建 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依赖于文件 B&#xff0…

【移动端】菜单的自动展开与收回

前言 为了满足手机上菜单栏随用户移动&#xff0c;菜单的自动展示与隐藏&#xff0c;特此记录 基本原理 实现逻辑 window.addEventListener(‘scroll’, debouncedScrollHandler) – 监听文档视图滚动事件 document.querySelector(‘.header’) – 选择器匹配元素 创建show和h…

中断门+陷阱门

中断门&#xff1a; 中断描述符在IDT表里面 kd> dq idtr 80b95400 83e48e000008bfc0 83e48e000008c150 80b95410 0000850000580000 83e4ee000008c5c0 80b95420 83e4ee000008c748 83e48e000008c8a8 80b95430 83e48e000008ca1c 83e48e000008d018 80b95440 000085000050…