结构体:
1、结构体类型的创建:
补充一点:结构体内部的变量赋不赋值都可以。
2、不完全声明结构体(省略掉结构体标签的结构体)的创建:
匿名结构体和结构体的区别是:
1、省略掉了结构体标签
2、结构体变量的创建就只有下图这一种方式,这也就意味着,如果你想使用该结构体,则在创建结构体时一定也要写上结构体变量,否则你就没法使用该结构体。
3、创建的结构体的类型与其他结构体的类型不会相同:
两个结构体的即使成员相同,但是仍不是同一类型。
3、结构体类型和int、double等类型的区别:
1、结构体类型需要先创建再使用,而int、double等可以直接使用。
2、结构体类型的书写方式为:struct student,而整形、浮点型的书写方式为:int 、double
注释:这里为了方便理解,将结构体标签写为student。结构体标签是在创建结构体时定义的。
4、结构的自引用:
通过在结构体内添加该结构体的指针实现结构体的自引用。
如果写成 下图这样 系统会报错。
原因:如果计算机处理器是32位时,指针大小为4byte,计算机处理器是64位时,指针大小是8byte,在固定的处理器中,指针大小是确定的。但是如果直接在结构体中直接自引用,该结构体的大小是无法确定的,这会使系统崩溃。
5、结构体变量的定义和初始化:(同一标签的结构体只能定义一次)
第一种:
第二种:
第三种:
初始化:
在这里我要额外补充一种结构体成员的赋值:数组
第一种方式是对数组直接初始化,第二种是对结构体初始化,此时如果用{}将数组中的元素括起来时,如果元素个数不足数组会自动补0,如果不用{},数组会自动获取元素,直到数组被填满,才会到下一个成员。(结构体中的成员赋值和初始化时如果都不用{}分割开,则只有第一个成员被填满才会轮到下一个成员)第三种方式,就是使用循环:
补充:在结构体中初始化数组时一定要在[]中写明元素个数,否则系统会报错。
6、结构体内存对齐:
在讲结构体内存对齐前我们先来看两个结构体:
为什么同一个结构体,只是成员的排序不同,他们所占的空间大小却截然不同呢?
这是因为结构体在内存中存储时需要进行内存对齐。
内存对齐规则:
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
1、第一个成员存放起点在与结构体偏移量为零的位置
2、第二个成员放在第一个成员后面,存放起点为对齐数的整数倍
3、结构体总大小为所有成员中最大对齐数的整数倍。
4、结构体的总偏移量必须是它最大成员字节数的整数倍(包括嵌套的结构体中的最大成员)。如果一个结构体B里嵌套另一个结构体A,结构体A的对齐数就是A中所有成员的对齐数的最大值,存放起点为对齐数的倍数,结构体A所占空间大小为A的大小。(例如:struct B里存有struct A,A里有char,int,double等成员,那A的对齐数是8,存放起点就是8的倍数)。
内存对齐参考资料:(16条消息) c语言结构体嵌套的对齐方式_binbinyantai的博客-CSDN博客_结构体嵌套结构体怎么对齐
为了方便读者理解,我再通过作图向大家展示:
存储方式:
虽然用了9个字节就已经将数据存储完了,但是由于此时结构体总大小,不是结构体成员中最大对齐数4的整数倍,所以仍旧会向下偏移,一直偏移到第12个格子。
结构体为什么要使用内存对齐?
为了提高程序运行效率。
如何即减少空间损耗,又提高运行效率?
在创建结构体时,将占用空间小的放在一起。
7、如何修改编译器默认对齐数?
可以使用#pragma pack()函数,使用前:
使用后:
8、结构体传参:
上述两种方式中,如果直接传结构体,系统需要为重新开辟一些空间,接收传过来的结构体。如果结构体较大,会产生空间浪费,通过地址传递,可以避免不必要的空间浪费。
位段
位段的用处:
能够将int、unsigned int、signed int、char型变量(整形家族都可以)在内存中所占空间的大小由字节级改为bit级。
如何使用位段?
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
使用位段时确保结构体中所有变量的类型都相同,因为当结构体中所有变量类型相同时,结构体
存储时就不会浪费字节。