在学习数学的时候,我们知道有一个操作叫做“合并同类项”,有助于简化自己的计算操作。
而在C语言里,我们尝尝苦于写变量名,比如str1,str2。谁记得住这些数组里,到底哪个是我需要的那个?
这个时候,结构体就出现了,犹如救世主一样。
一、结构体是什么?
如图是一个结构体的演示。
其中,struct为结构体关键词,Stu为结构体类型,里面的name、grade、age是该结构体的成员变量(本质上仍是变量)
二、结构体的初始化
结构体的初始化可以有多种形式。
(1)按顺序初始化
(2)不按顺序初始化
随意的赋值,但是第一行按顺序初始化,第二行则不按顺序初始化。
第二种比较自由(而且VS这种有提示词的,可以帮助看一下哪个变量还没有赋值)缺点是赋值的时候有点累,需要先指向成员变量再赋值。
第一种按照顺序赋值即可,缺点是成员变量多时,可能记不住顺序。
三、结构体的特殊声明
我们在结构体声明时,可以不完全声明。
我们称之为匿名结构体。
但是这种结构体不重命名的情况下,难以二次使用,所以不建议使用匿名结构体。
四、结构内存对齐
有没有好奇宝宝想试试看sizeof(结构体)的呢?
这个时候会发现,有些情况下符合我们的认知,有些则不能。
比如以下两个式子。
明明这个时候两个结构体存储的东西都一样,为什么内存大小不一样呢?
而且,按照原先我们的认知,Stu和Stu1难道不应该都是10个字节的大小吗?为什么变成了12个字节呢?(4+4+1+1=10)
这个时候,结构体的内存对齐就闪亮登场了!
(1)什么是内存对齐?

grade是int类型,所以对齐数为4。所以grade不能放在偏移量为1的地方(即name之后)而是放在偏移量为4的地方。
而后的name2,类型为char,对齐数为1,直接放在后面即可。
再后的age,类型为int,对齐数为4,所以应该放在偏移量为12的地方(4+4+4)。
也就得到了16的结果(4+4+4+4)
同时做个小练习,这个结构体的大小为什么是12?
(2)为什么存在对齐?
大部分参考资料是:
1、部分设备存在硬件问题,某些硬件平台只能在某些地址取某些特定类型的数据,否则则会硬件异常。
2、数据结构应尽可能在自然边界上对齐。当读取到double类型时,处理器总是从内存里提取8个字节。如果double类型没有被对齐,那么处理就至少需要两次内存访问才可以得到这个double的内容。
所以,实际上对齐的行为是以空间换时间的行为。
所以像上面两个例子,我们应该将比较小的部分全都放在一起,减少浪费的空间。
(3)对于结构体内存有什么解决方法?
答:有,甚至能进一步缩小结构体所占内存。但是功能越强,安全性的问题也会凸显。
此物名曰——位段
位段
位段的声明和结构是类似的,有两个不同:
位段的成员必须是 int、unsigned int 或 signed int ,在C99中位段成员的类型也可以选择其他类型。 位段的成员名后边有⼀个冒号和⼀个数字。
(还是Stu)
如图便是位段的使用。
需要注意的是,冒号后方的数字,是该成员变量占用的bit位个数。
我们知道1byte=8bit。而我们以前认为的最小的空间是char的1byte。
所以学会了位段,可以称为空间管理大师了。
需要注意的是,由于1个字节1个地址,所以我们不能直接scanf访问改变其中的变量。
而是通过先给一个变量scanf,然后再访问结构体为成员变量赋值。