C语言 day17 | 我的日常分享

C语言 day17

结构体-结构体的内存分配

引入

1
2
3
4
5
6
struct data{
char c;
int i;
};
struct data stu;
printf("%d\n",sizeof(stu));
  • 问:上面代码的输出结果为什么?5?

运行结果:
图片

分析:char一个字节,int四个字节,为什么不是5字节呢?32位处理器一次只能处理32位,也就是4个字节的数据,64位处理器一次就能处理64位,即8个字节的数据。看图—>
图片
由图可得,上面代码输出的是4字节。

结构体大小 >= 成员总大小


结构体内存对齐

对齐规则(重要)

  • 步骤:

    1. 确定分配单位:每行应该分配的字节数,由结构体中最大的基本类型长度决定
    2. 确定成员的起始位置的偏移量:成员的自身基本类型的整数倍x(0到n),如果空间已经被使用了,则x+1继续偏移,直到遇到没有被使用的空间
    3. 收尾工作:确定结构体总大小,总大小为分配单位的整数倍,即开辟的行数乘以分配单位
  • 例子:

1、

1
2
3
4
5
6
struct data{
int a;
char b;
short c;
char d;
};

内存分布:
图片

2、

1
2
3
4
5
6
7
struct data{
char a;
short b;
short c;
int d;
char e;
};

内存分布:
图片
3、

1
2
3
4
5
6
struct data{
char a;
short b;
char c;
short d;
};

内存分布:
图片


结构体嵌套结构体

1
2
3
4
5
6
7
8
9
struct data1{
int x;
int y;
};
struct data2{
int a;
int b;
struct data1 c;
};
  • 结构体变量c,作为了struct data2的成员,叫做结构体嵌套结构体

案例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
struct data1{
int x;
int y;
};
struct data2{
int a;
int b;
struct data1 c;
};
int main(int argc,char *argv[]){

//嵌套结构体初始化
//struct data2 stu={10,11,12,13};//这样也可以,不推荐
struct data2 stu={10,11,{12,13}};//仍然需要按照顺序

//嵌套结构体的赋值
stu.c.x=100;

//嵌套结构体的访问
printf("%d %d %d %d\n",stu.a,stu.b,stu.c.x,stu.c.y);
return 0;
}

运行结果:
图片

注意:stu.c是没意义的,因为对于计算机来说,他要操作的是数据,那你说stu.c是个什么,取出来是什么?啥都不是,但是会打印出c中的第一个元素空间的内容。不要这样干就行了。


结构体嵌套结构体的内存对齐

先将嵌套的结构体进行上面的内存对齐,再将嵌套的结构体看成一个变量进行下面的步骤,其实跟上面的一样

  • 步骤:
    1. 确定分配单位:每行应该分配的字节数,所有结构体中最大的基本类型长度。
    2. 确定成员的起始位置的偏移量:成员的自身基本类型的整数倍x(0到n),如果空间已经被使用了,则x+1继续偏移,直到遇到没有被使用的空间
    3. 收尾工作:确定结构体总大小,总大小为分配单位的整数倍,即开辟的行数乘以分配单位
1
2
3
4
5
6
7
8
9
10
struct A{
short e;
char f;
};
struct B{
int a;
short b;
struct A c;
short d;
};

内存分布:
图片

1
2
3
4
5
6
7
8
9
10
struct A{
short d;
char e;
int f;
};
struct B{
short a;
struct A b;
short c;
};

内存分布:
图片


指定对齐规则(强制类型对齐)

  • 使用#pragma pack改变默认对齐原则

  • 格式:#pragma pack(value)

  • 注意:

    1. value只能是1、2、4、8等即2ⁿ;
    2. 指定对齐值与数据类型对齐值相比取较小值。
  • 步骤:

    1. 确定分配单位:每行应该分配的字节数,分配单位为min(value,默认对齐字节)
    2. 确定成员的起始位置的偏移量:成员的自身基本类型的整数倍x(0到n),如果空间已经被使用了,则x+1继续偏移,直到遇到没有被使用的空间
    3. 收尾工作:确定结构体总大小,总大小为分配单位的整数倍,即开辟的行数乘以分配单位

案例:

1
2
3
4
5
6
#pragma pack(2)
struct data{
char a;
int b;
short c;
};

分析:不加之前结构体总大小为12字节;加了#pragma pack(2)之后结构体的总大小为8字节

结构体的成员顺序,会影响结构体的总大小;如果想节约空间,则可以把字节数差不多的类型放在一起,但是这样访问效率会下降。