结构体的内存

本文讨论了结构体的自引用问题,指出在结构体中直接引用未定义的结构体会导致死循环,而通过指针引用可以解决这一问题。接着,文章深入探讨了结构体内存对齐的规则,包括每个成员的地址间隔、内存浪费情况以及结构体总大小的计算方式。通过实例和图表,清晰地解释了编译器如何对结构体进行内存布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结构体的自引用:

例如有这样的代码

struct student{
	char name[1024];
	int age;
	struct student a;
};

此时我们编译执行后,程序会报错(a使用未定义的struct student),原因很好分析,例如我们想求这个结构体的所占字节大小,student 占的字节就是 char[1024]+int+student ,此时student又是不知道的,就会返回一个死循环。
但如果需要自引用本身结构体,只需要在第四行做一下改动

struct student{
	char name[1024];
	int age;
	struct student* a;
};

因为我们直到指针变量都是四个字节,这样就可以确定所占内存空间大小。

结构体内存对齐:

我们先看代码

typedef struct Test{
	char a;
	int b;
	int c;
}Test;

int main(){
	Test t;
	printf("%p\n", &t);
	printf("%p\n", &t.a);
	printf("%p\n", &t.b);
	printf("%p\n", &t.c);
	printf("%d\n", sizeof(t));
	system("pause");
	return 0;
}

在这里插入图片描述
我们发现每个元素的地址间相差4个字节,并且整个结构体变量所占字节大小位12
我用一张图来表示一下
在这里插入图片描述
这里我们发现第一个char元素之后,有三个字节是没有用上的,我用蓝色来表示

将代码改一下

typedef struct Test{
	short a;
	short b;
	int c;
}Test;

int main(){
	Test t;
	printf("%p\n", &t);
	printf("%p\n", &t.a);
	printf("%p\n", &t.b);
	printf("%p\n", &t.c);
	printf("%d\n", sizeof(t));
	system("pause");
	return 0;
}

在这里插入图片描述
用图表示在这里插入图片描述
看到这里就有点懵逼了,有的时候浪费了内存空间,有的时候则没有浪费

这里就要介绍一下结构体的内存规则了

  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(对齐数: 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8
  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

我们再举个结构体来解释一下:

typedef struct Test{
	short a;                    //a放在偏移量为0的位置
	int b;                      //8 4=> 4 b就要放在偏移量4的整数倍上
	char c;                     //8 1=> 1 c就要放在偏移量1的整数倍上
	short d;                    //8 2=> 2 d就要放在偏移量2的整数倍上
}Test;

用图来表示如下
在这里插入图片描述

也可以手动修改对齐数

#pragma pack(1)
//把默认对齐数设成1
#pragma pack()
//还原
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值