结构体知识点
前言
这篇文章记录了一名初学者的学习过程。如果内容有误,请大家提出建议。小编将不断改进,力求创作出令大家满意的博客
结构体的创建与初始化
结构体的定义使用关键字 struct + 结构体的名称和一组花括号 {}在其中进行书写成员变量。成员变量可以是任意类型的数据,包括、数组、指针、甚至是其他结构体。
结构体的初始化可以是声明初始化(也就是上方的图片形式)还可以使用typedef进行初始化。
匿名结构体
匿名结构体创建是为了方便程序员简写,以便快速的对成员变量进行访问。
但是匿名结构体变量即使俩者内部成员变量一致,也无法进行赋值操作。
解析:c语言中是不允许隐性类型转换以及赋值操作的
解决方法:
1、使用相同的结构体变量(俩者都使用s1或者p2)
2、重新命名一个结构体变量,并创建包含该结构体的新结构体变量,可以使用命名结构体类型。然后,创建两个新的结构体,这两个结构体内部都包含这个命名结构体。最后,通过初始化的名字访问嵌套结构体的成员。
结构体的自引用
通过自己传入数据,数据进行接受。若按照struct Node next方式进行书写程序会显示该类型未初始化,实则程序会陷入无休止的调用,对自身进行调用,内部存在int 执行完接着进行调用。
结构体的内存对齐
对齐规则:
1、Vs编译器上默认对齐数为8,而在其他编译器默认对齐数是该类型的字节数(int类型占 4个字节,这个4个字节就是它的默认对齐数),编译器会选取最小的对齐数作为偏移量。(在vs中默认对齐数可以通过 #pragma pack(数值)进行修改)若不想修改默认对齐数可以放置#pragma pack( )
举例:int 为4 默认对齐数为8 选取一个最小的,作为偏移量
2、结构体的第一个成员变量的起始位置偏移量为0.
3、对于每个结构体成员变量,选择其自身字节数和默认对齐数中较小的一个作为对齐数。成员变量的起始位置必须是其对齐数的倍数(如果不是倍数,编译器会在当前偏移量上增加必要的字节数以达到对齐数的倍数)。
4、嵌套结构体,按照内部结构体成员变量的最大对齐数进行对齐。
习题一
解析:(VS情况下)起始位置为0,默认对齐数为8,选取最小的。char类型的字节数为1所以char a 、char b分别对应0和1,int 为4个字节,默认对齐数为8,偏移量为4(红色为int所存放的空间)。至于中间2和3可以理解为空间换取效率。
习题二
(结构体的起始位置为0)int 占4个字节,默认对齐数为8,选取最小的。(int占0和4的空间),char 占1个字节,默认对齐数为8,放在5.接着double占8个字节,默认对齐数为8,占用8和16空间。**最后总占用16个字节。**当我们做完上述的俩道题,会好奇为什么程序会在内存中浪费一些空间?
例子:假如程序是按照4个字节进行访问,而结构体内部存储的是char a;int b;
按照第一种程序是连续存放的,一次访问4个字节(char 占一个字节,int 占4个字节)当访问4个字节时,内容包含了char 和int ,若再次访问会造成越界访问。
使用第二种程序是不连续存放,则可以有效的避免越界访问这一问题。(尽量将占用空间小的类型存放在一起)
嵌入结构体如何计算?
解析:先从double d开始,默认对齐数为8字节占用(0~8的空间)。接着结构体s1,共占用16个字节
选取struct s1中的最大对齐数为 8,该类型的起始位置为8
解析:
1、double d开始,默认对齐数为8字节占用(0~8的空间)。
2、结构体s1,共占用16个字节选取struct s1中的最大对齐数为 8,该类型的起始位置为8.占用空间为8到24。
3、int占用4个字节(偏移量必须是倍数,25、26、27都不是4的倍数,所以省略)跳转到28.
最后结果为32
结构体传址和传值
传址调用:
当结构体通过传址调用时,函数接收到的是结构体的指针。对指针所指向的数据进行修改将直接影响原始结构体。这种方法在数据量较大时更为高效,因为传递指针的开销较小。
传值调用:
当结构体通过传值调用时,函数接收到的是结构体的一个副本。对该副本的修改不会影响原始结构体。这种方法在数据量较小时适用,因为传值会产生额外的内存开销。
位段的实现
什么是位段?位段是在内存有限的环境中或需要直接操作硬件寄存器时。它允许我们精确地控制结构体成员的位宽,从而实现内存优化和高效的位操作。(常用于嵌入式中)
仅限于int 、 unsigned int 、 signed int、char。
书写格式:字符类型+_下划线元素名字+:冒号 数值
位段中的位是二进制位也就是数值部分(一个二进制位为比特位,整型是4个字节。8个bite位换算成一个字节,总共32个字节,超出int自身的大小,编译器会报错)
位段也存在内存对齐
位段中的位是二进制位,也等于bite位。
解析:
1、char_s 占用5个bite位,内存中还剩下3个bite位,此时剩下的3个bite位为内存损耗。
2、char_b 为4个bite位,则需要开辟新的内存空间,8个bite位存放4,剩下4个无法存储下一个位段,则又开辟新的内存。
3、char_c 为8个bite位刚好存下剩下的内容。
总结:内存并不会将剩下的bite位进行组合,而是会忽略这一部分。
那如何在位段中进行插入数据?
内存调试也是按照这样的思路进行展示
(这里的0a为为16进制:0、1、2、3、4、5、6、7、8、9、a、b、c、d、E、f、g)
完结!!