C语言进阶第八篇【三大自定义类型详解:结构体struct,枚举enum,联合union】(下)

简介: C语言进阶第八篇【三大自定义类型详解:结构体struct,枚举enum,联合union】(下)

1.6 修改默认对齐数

#pragma预处理指令,可以改变我们的默认对齐数;修改命令是:#pragma pack(n)


❤️例1:

c233d878b58f47f69bf51ac25e38d9cc.png



⭐️按照默认对齐数8来计算:

12be21a9777146e5903db86a316bcf7c.png



通过画图我们知道,此时大小应该是16,16刚好是8的倍数;所以最终结果就是16!


⭐️按照修改的对齐数4来计算:

7053409547b242a8bb6ea8c535f61ad8.png



通过画图我们知道,此时大小应该是8,8刚好是8的倍数;所以最终结果就是8!


❤️例2:

e208eee269c84065a171ac88157e99ba.png



这里就不在画图了,感兴趣的小伙伴自己动手画图试试吧!


⭐️按照默认对齐数8来计算:


c1从偏移量0处开始,且占一个字节;


i占4个字节,对齐数取4和8的较小值;应从4的倍数4开始,占四个字节:4、5、6、7;


c2从8开始,且占一个字节;所以最终就是0-8共9个字节,取4的倍数就是12!


⭐️按照修改对齐数2来计算:


c1从偏移量0处开始,且占一个字节;


i占4个字节,对齐数取4和2的较小值;应从2的倍数2开始,占四个字节:2、3、4、5;


c2从6开始,且占一个字节;所以最终就是0-6共7个字节,取2的倍数就是8!


⭐️按照修改对齐数1来计算:


c1从偏移量0处开始,且占一个字节;


i占4个字节,对齐数取4和1的较小值;应从1的倍数1开始,占四个字节:1、2、3、4;


c2从5开始,且占一个字节;所以最终就是0-5共6个字节,取1的倍数就是6!


1.7 offsetof 库函数的使用

offsetof库函数是计算结构体中某变量相对于首地址的偏移;引用的头文件是<stddef.h>;对于怎么模拟实现offsetof,我们以后回说!这里暂时只掌握如何使用即可!


size_t offsetof( 结构体, 每个成员变量 )


26f38adfa1ad4475a6372c81e770fe28.png


1.8 结构体传参

对于结构体的传参,有两种形式:一种是传值调用;一个是传址调用!我们首选传址调用,为什么呢?


(1)函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

(2)如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。


❤️例:

b3ec85e5964e41aba135c4b460aa733a.png



2. 位段

2.1 什么是位段

位段的声明和结构是类似的,有两个不同:

    (1)位段的成员必须是 int、unsigned int 或signed int等 。

    (2)位段的成员名后边有一个冒号和一个数字。


❤️例:


c8465828bfba414d9c0166ecf0d0dcc8.png


2.2 位段的内存分配

注意:


1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

总结:位段的意义,是节省内存空间,根据实际的要求来分配(按需分配)所需要的空间。位段分配空间是按照比特位来分配的,一个字节 = 8个比特位!


❤️例:

8ad9b7bf7e964c32a7548f68329d6411.png



解释:


对于整型数据int我们就一次开辟4个字节32个比特位;对于浮点型数据char我们就一次开辟1个字节8个比特位!


(1)整型数据,先开辟4个字节32比特位;对于_a占2个比特位,所以还剩下30个比特位;


(2)对于_b占5个比特位,所以还剩下25个比特位;


(3)对于_c占10个比特位,所以还剩下15个比特位;


(4)对于_d占30个比特位,还剩下的15个比特位完全不够用,所以又需要开辟4个字节32比特位;所以总共使用了8个字节!


注意:但是对于(4)的使用,是先使用了(3)剩余的15个比特位,在使用新开辟的;还是把上面的15个比特位直接舍去,全都使用新开辟的空间?这就是一个问题!所以位段肯定是不跨平台的!


2.3 位段的跨平台问题

(1)int 位段被当成有符号数还是无符号数是不确定的。

(2)位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。)

(3)位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

(4)当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。


总结:跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。


❤️例:利用一个例子来验证VS中位段是从左到右分配还是从右到左分配?是舍弃剩余还是利用剩余?


b27e11e8d2ad4e84bd70f451f42e9102.png


画图分析一下:

3f47ee97fd334730a25ba601504716bf.png



总结:


(1)在VS中,位段中的成员在内存中从右向左分配(从低地址到高地址分配)!


(2)在VS中,多余的比特位不够用,是直接舍去,开辟新的空间后直接用新的!


(3)大小端讨论的是字节序,一个字节内部的顺序和大小端是没有关系的!


2.4 位段的应用

这实际上是属于计算机网络的内容;目前只做简单了解就好!


就是给你要发送的数据加上一些数据包的信息,利用位段来分配位数,比较节省空间!


5032649da2334a1f881305251f90ef46.png


3. 枚举

3.1 枚举类型的定义

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


❤️例:


d5deca22f2da49dd860f7523cedf7deb.png


以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。{}中的内容是枚举类型的可能取值,也叫枚举常量 。这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。


3.2 枚举类型的优点

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


枚举的优点:

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

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

3. 防止了命名污染(封装)

4. 便于调试

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


3.3 枚举类型的使用

枚举类型就是一种类型不是整型;枚举是类型,可以定义变量,但其成员是常量!


枚举类型的大小就是一个整型变量的大小:4


❤️例:


214a833dc4d344828ab05b562a6b4451.png


实际应用:我们在设计计算器时,对于case里面的语句,我们使用数字(1 2 3 4)还要思考对应是要执行什么操作?但是如果定义一个枚举,此时case 1:我们就可以直接写成case ADD: 直接就能出来这个选项是要执行什么操作,增加可读性!


4. 联合(共用体)

4.1 联合类型的定义

联合也是一种特殊的自定义类型;这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。


❤️例:

22a841dfb13c43c6a48912354a0361d7.png



4.2 联合的特点


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


❤️例1:


c31186ad7ecf43e685bac39b1263d6dc.png


怎么理解呢?我们通过画图来分析一下:


c70a04e114ba41718331529241f92c95.png


❤️例2:统一初始化


66f52f04ffa44f6a9ee52a196a2f5cb3.png


❤️例3:分开初始化


8a025281d017423185a252ca4a838035.png


为什么会这样呢?因为对于u.i = 10 初始化的值会替换u.i = 1000上,原来对应的比特位;最终就会造成u.i结果不在是1000;所以在分开初始化的时候,一次只能使用一个!


4.3 联合的实际应用

比如:我们可以利用联合来判断大小端存储!


❤️例:


a911a318685e4431adf6260aa145c92d.png


解析:


我们给i赋值为1;如果在大端模式,在内存中存储就是00 00 00 01,那么我们取出c,虽然c并没有赋值,但是联合体共用同一块内存,所以取出来c的值也就是0。如果在小端模式,在内存中存储就是01 00 00 00,那么我们取出c,虽然c并没有赋值,但是联合体共用同一块内存,所以取出来c的值也就是1。

e2583f2c10d34d6bad5ea9e362b4d2a7.png



测试结果:


a5370903f95e40ddbaf3ccf5390db942.png


4.4 联合大小的计算


联合大小的计算

1.联合的大小至少是最大成员的大小--------不一定就是最大成员的大小

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


❤️例1:


7cbcf163b3184180a7788e0fbaeba330.png


char对齐数是1,数组a[5]占5个字节;int i 对齐数是4,且占4个字节!我们取两者最大值5;并且看5是不是最大对齐数4的倍数;不是还是要在浪费3个字节,补充到8个字节;最终结果就是8!


❤️例2:


571258dcc5924fb1b84c2e1c10af6d57.png


short本身占2个字节,对齐数也是2,s[5]总共就占10个字节;int i 对齐数是4,且占4个字节!我们取两者最大值10;并且看10是不是最大对齐数4的倍数;不是,还是要在浪费2个字节,补充到12个字节;最终结果就是12!


结束语

今天的分享就到这里,想要提升编程思维的,快快去注册牛客网开始刷题吧!各种大厂面试真题在等你哦!


💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站

184068dc41e94efbb14e555f972eaa17.png

相关文章
|
1月前
|
存储 数据可视化 编译器
【C语言】union 关键字详解
联合体(`union`)是一种强大的数据结构,在C语言中具有广泛的应用。通过共享内存位置,联合体可以在不同时间存储不同类型的数据,从而节省内存。在嵌入式系统、硬件编程和协议解析等领域,联合体的使用尤为常见。理解和正确使用联合体可以使代码更加高效和灵活,特别是在内存受限的系统中。
104 3
【C语言】union 关键字详解
|
11天前
|
C语言
【C语言程序设计——循环程序设计】枚举法换硬币(头歌实践教学平台习题)【合集】
本文档介绍了编程任务的详细内容,旨在运用枚举法求解硬币等额 - 循环控制语句(`for`、`while`)及跳转语句(`break`、`continue`)的使用。 - 循环嵌套语句的基本概念和应用,如双重`for`循环、`while`嵌套等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台将对编写的代码进行测试,并给出预期输出结果。 5. **通关代码**:提供完整的代码示例,帮助理解并完成任务。 6. **测试结果**:展示代码运行后的实际输出,验证正确性。 文档结构清晰,逐步引导读者掌握循环结构与嵌套的应用,最终实现硬币兑换的程序设计。
42 19
|
11天前
|
C语言
【C语言程序设计——枚举】得到 3 种不同颜色的球的可能取法(头歌实践教学平台习题)【合集】
本关任务要求从红、黄、蓝、白、黑五种颜色的球中,每次取出3个不同颜色的球,列举所有可能的排列情况。通过定义枚举类型和使用嵌套循环语句实现。枚举类型用于表示球的颜色,循环语句用于生成并输出所有符合条件的排列 编程要求:在指定区域内补充代码,确保输出格式正确且完整。测试说明:平台将验证代码输出是否与预期一致,包括每种排列的具体顺序和总数。 示例输出: ``` Output: 1 red yellow blue 2 red yellow white ... 60 black white blue total: 60 ```
31 4
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
163 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
195 10
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
C语言
《C语言及程序设计》实践项目——枚举应用
返回:贺老师课程教学链接 【项目1-对称点】 设计函数,可以按指定的方式,输出一个平面点的对称点 下面给出枚举类型定义和main函数(测试函数),请写出output函数的实现。 #include&lt;stdio.h&gt; enum SymmetricStyle {axisx, axisy, point};//分别表示按x轴, y轴, 原点对称三种方式 void
1099 0
|
11天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
49 23
|
11天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
41 15
|
11天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
50 24

热门文章

最新文章