C语言的相关面试中,对结构体大小的考察是可以体现出一个程序员对内存分配的理解,它会涉及到栈的生长方向(也就是高位地址在上,低位地址在下)和内存生长方向(大小端),以及各种数据类型的内存占比大小,本文会通过浅显易懂的方式给大家讲解结构体的内存分配。
结构体是各种成员的结合体,它的大小可以笼统理解为每个成员的大小之和。
本文以32位系统举例,在VS环境下的情况,Linux系统中大家可以自行测试验证。
目录
1.基本数据结构的大小
了解结构体的内存分配首先要了解常用的数据类型的大小,每种数据的大小集合一起构成结构体大小。
基本数据类型 | VS中内存大小 |
short int | 2字节 |
int | 4字节 |
float | 4字节 |
double | 8字节 |
char | 1字节 |
int*/char*/指针 | 4字节 |
例如:
#include<stdio.h>
struct stu {
int a;
int b;
};
int main
{
struct stu a;
printf("%d\n",sizeof(a)); //4+4=8
return 0;
}
2.结构体内存分配原则
知道了基本数据类型的大小后,就可以根据结构体内存分配的原则判断结构体的大小。
(1)以成员中占字节数多的,以它的大小为单位开辟内存
比如结构体成员中只有 char 型数据 ,以 1 字节为单位开辟内存。这个结构体的大小就是1的倍数。
成员中存在char、int型,int型数据占字节最大,以 4字节为单位开辟内存。这个结构体的大小就是4的倍数。
(2)字节对齐
结构体中char 型数据,1 字节对齐 ,即存放 char 型的变量,内存单元的编号是 1 的倍数即可。
结构体中int 型数据,4 字节对齐 ,即存放 int 型的变量,起始内存单元的编号是 4 的倍数即可。
3.示例演示
结构体开辟内存的时候,按照结构体的数据顺序从开始位置进行开辟。
#include<stdio.h>
struct stu{
char a;
short int b;
int c;
}a;
int main()
{
printf("%d\n",sizeof(a));
printf("%p\n",&(a.a));
printf("%p\n",&(a.b));
printf("%p\n",&(a.c));
return 0;
}
打印结果:
sizeof(a) = 8
a.a 的地址和a.b的地址相差2;a.b 的地址和a.c的地址相差2。
内存分配如图所示:
结构体首先按照最大数据开辟空间,最大是int型,开辟4个字节空间。
从第一个成员a开始存放,char 型数据a 只需要1个字节,再存放第二个数据short int型,它需要2个字节空间,需要遵循字节对齐的规则,因此0x0000 0001不能存放,在0x0000 0002开始存放short int型的元素b,此时第一个开辟的4个空间使用完毕。
再开辟4个字节空间继续存放数据,存放第三个数据int型,它正好占4个字节。
因此,整个结构体需要4+4=8 个字节空间存放三个成员。
结构体开辟内存空间是从开始依次进行开辟的,如果将上述结构体中的元素顺序修改,结构体的大小就完全不同的。
#include<stdio.h>
struct stu{
char a;
int c;
short int b;
}a;
int main()
{
printf("%d\n",sizeof(a));
printf("%p\n",&(a.a));
printf("%p\n",&(a.c));
printf("%p\n",&(a.b));
return 0;
}
打印结果:
sizeof(a) = 12
a.a 的地址和a.c的地址相差4;a.c 的地址和a.b 的地址相差4。
内存分配如图所示:
这个结构体也是依据int型 进行开辟空间。
首先开辟4个空间,存放char型 a成员,遵循字节对齐的规则,再开辟4个字节存放第二个成员int型,再开辟4个字节空间,存放第三个成员short int型。因此,该结构体的大小是4+4+4=12个字节。
4.总结
结构体是基本数据类型的集合,结构体的大小是按序进行开辟空间存放,遵循字节对齐的原则,通过字节对齐可以看出,c语言中是用空间换时间,提高CPU的读取效率 。
如果不字节对齐,某些数据需要读取多次,降低了读取效率。例如:结构体中char型和int型两种数据,如果没有字节对齐,char存放1个字节,在下一个字节中存放int型,cpu 只能读取3个字节,再下一次读取int中的最后一个字节,导致int型数据需要两次读取才能完成。