一.结构体
1.概念
与数组不同 它的成员类型 可以是不同类型
2.声明一个结构体类型
struct是结构体关键字 Stu是结构体标签
3.创建变量
只有s1 s2 是局部的结构体变量 其余的都是全局变量
4.错误示范
编译器会把这两种匿名结构体 当作单独的两种结构体
因此不可以用psa去存放sa的地址
5.
结构体的自引用是不可以直接进行引用的
会类似为一种死递归下去
一个n又调用一个n 无限循环下去 无法计算
正确自引用的示例
我们必须找到一个相同类型的指针类型去引用它
6. typdef 重命名
注意这里的Node 不可以省略 不可以用匿名结构体类型
7.定义方式
8.
结构体初始化以及结构体访问打印
嵌套初始化
st c a d 是结构体标签S的结构体对象
weight age 是结构体标签T的结构体对象
当要打印时 用创建的变量s去访问即可 s.c
这里的st是T的结构体对象
打印时 s.st.weight 去打印体重
创建的变量s . 一下就代表访问一层 .一下就代表访问一层
9.结构体内存对齐
例子一
最大对齐数是8
8+1+3+4=16 16是最大对齐数8的倍数
嵌套结构体的计算
例子
答案是32
解析如下
一开始从偏移量0开始 那么c1占完指向1
开始存放s3
根据嵌套的定义 那么按照s3中成员最大对齐数的整数倍开始对齐
那么我们就要浪费空间
过程为 1+7+16+8=32
在包含嵌套结构体在内的所有成员的最大对齐数是8
那么32是8的倍数 因此不用变化
故答案为32
如图所示·
为什么要存在内存对齐呢?
如何设计结构体?
对默认对齐数的设定方式
取消与设定默认对齐数
偏移量
偏移量是一种相对的量度 c的偏移量是0
表示它相对最初刚开始存放的位置 偏移量为0
i 的偏移量为4 代表它相对最初存放的位置的距离是4
这个偏移量就是成员变量刚开始存放的起始位置
d 的偏移量为8
代表它从相对最初开始的0 距离为8处开始存放8个字节
调用 offsetof 函数计算偏移量
参数为 结构体名 和 结构体成员名 返回的是偏移量
10.结构体传参 必须传地址
以下是错误示范
tmp的改变不会影响 成员的初始值
正确的方法 传地址
当初始化之后 可以用Print打印 打印时可以传地址 也可以传参
哪一种更好?
当然传地址更好 为什么?
因为传地址
只是穿过去了一个地址 地址只占用4个 或 8个字节
然而如果传结构体
如果结构体过大
那么会导致结构体传过去的那个参数受不了
函数的参数会压榨着系统开销会比较大
如图所示总结
位段
位是指 二进制位
不会有什么float double类型出现
如果成员是char类型 那么全是char类型
int类型存在的定理 同上句
位段的内存分配的规则
重点在第二句
a后面冒号 后面是2
表示a在内存空间中占用2个bite位
b同理占5个比特位 c d分别占用 10个 30个比特位
由于位段分配内存空间是以1个字节 或者4个字节为单位进行分配的
所以当一个int 整形空间中不足以存放下一个变量时 我们需要舍弃这块空间
重新开辟一块相同单位大小字节的空间
我们根据位段后面的比特位大小来决定每次开辟内存空间的大小
成员变量a 的值等于10 00000000000000000000000001010
存位段中时
存的是010 因为它只有三个比特位大小
b是20 000000000000000000000000000000010100
但只能存4个比特位 即是存0100
c d同理
注意当存储时 填补不满比特位 那么前面补0
位段的跨平台问题
枚举
默认第一个为0 依次加一
枚举的大小
联合体
大小端存储方式
大小端存储的判断
方法一
利用char*强制转化 每一次解引用访问一个字节
方法二
把u.i赋值为1
联合体计算大小
这里的数组相当于 五个char 类型的元素
总结
位段是不存在对齐的
联合体 结构体都是存在对齐的