✅<1>主页:C语言的前男友
📃<2>知识讲解:结构体,声明,变量初始化,结构体内存对齐
🔥<3>创作者:C语言的前男友
☂️<4>开发环境:Visual Studio 2022
💬<5>前言:关于结构体我们已经不陌生了,今天我们就来系统的聊一聊结构体的声明,初始化,结构体占的内存大小。
目录
🍂八.修改默认对齐数
🍃例一:
🍃例二:
🍂最后:
- //结构体声明
- struct Stu
- {
- char name[20];//名字
- int age;//年龄
- char sex[5];//性别
- char id[20];//学号
- };

在声明结构的时候,可以不完全的声明——匿名结构体类型。
- //匿名结构体类型
- struct
- {
- int a;
- char b;
- float c;
- }x;
- struct
- {
- int a;
- char b;
- float c;
- }a[20], *p;
上面的两个结构在声明的时候省略掉了结构体标签。
那么问题来了?在上面代码的基础上,下面的代码合法吗?
p = &x;
注意:编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。
在结构中包含一个类型为该结构本身的成员是否可以呢?
- struct Node
- {
- int data;
- struct Node next;
- };
- 可行否?如果可以,那sizeof(struct Node)是多少?

这里显然是不行的。但是是不是就意味着就不行了呢?还是有办法实现自引用的。
- 正确的结构体自引用方式
- struct Node
- {
- int data;
- struct Node* next;
- };
- 如果加上 typedef 是不是就可以这样实现结构体自引用呢?
-
- typedef struct
- {
- int data;
- Node* next;
- }Node;
- 这样写代码是不行的
-
- 解决方案:
- typedef struct Node
- {
- int data;
- struct Node* next;
- }Node;
-
- struct Point
- {
- int x;
- int y;
- }p1; //声明类型的同时定义变量p1
- struct Point p2; //定义结构体变量p2
-
- //初始化:定义变量的同时赋初值。
- struct Point p3 = {x, y};
-
- struct Stu //类型声明
- {
- char name[15];//名字
- int age; //年龄
- };
- struct Stu s = {"zhangsan", 20};//初始化
-
- struct Node
- {
- int data;
- struct Point p;
- struct Node* next;
- }n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
- struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
- struct Stu
- {
- char name[20];
- int age;
- char ID[20];
- };
- int main()
- {
-
- 按照结构体顺序初始化变量
- struct Stu stu2 = { "ikun",20,"JNTM123" };
- 自定义顺序初始化变量
- struct Stu stu1 = { .ID = "CZU123",.age = 19,.name = "张三" };
-
- return 0;
- }
我们已经掌握了结构体的基本使用了,那么一个结构体到底时多大呢?到底怎么计算呢?
- struct S1
- {
- char c1;
- int i;
- char c2;
- };
- struct S2
- {
- char c1;
- char c2;
- int i;
- };
- int main()
- {
- printf("%d\n", sizeof(struct S1));
- printf("%d\n", sizeof(struct S2));
- return 0;
- }
大家可以猜一下结果

结果是不是出乎大家的意料了,虽然结构的成员都是一样的,但是结构的大小却不一样。
到底是为什么造成这样的结果呢?其实结构体的大小可不是简单的结构体成员大小加在一起的。
而是有一种内存对齐的规则。
结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认的值为8)
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
下面我们就对着这个规则来做几个例子:
- struct S1
- {
- char c1;
- int a;
- char c2;
- };
- 求结构体s1的大小

运行效果:

- struct S2
- {
- char c1;
- char c2;
- int i;
- };
- 求结构体 S2 的大小
3.运行效果:
- struct S1
- {
- char c1;
- int a;
- char c2;
- };
- struct S2
- {
- char c1;
- struct S1 S;
- char c2;
- int i;
- };
- //求结构体S2的大小

运行结果:

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。
结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。
例如:
- struct S1
- {
- char c1;
- int i;
- char c2;
- };
- struct S2
- {
- char c1;
- char c2;
- int i;
- };
s2就比s1更节省空间。
#pragma pack();
- #include
- #pragma pack(8)//设置默认对齐数为8
- struct S1
- {
- char c1;
- int i;
- char c2;
- };
- #pragma pack()//取消设置的默认对齐数,还原为默认
- #pragma pack(1)//设置默认对齐数为1
- struct S2
- {
- char c1;
- int i;
- char c2;
- };
- #pragma pack()//取消设置的默认对齐数,还原为默认
- int main()
- {
-
- //输出的结果是什么?
- printf("%d\n", sizeof(struct S1));
- printf("%d\n", sizeof(struct S2));
-
- return 0;
- }
运行结果:

- #include
- #pragma pack(1)//设置默认对齐数为8
- struct S1
- {
- char c1;
- int i;
- char c2;
- };
- #pragma pack()//取消设置的默认对齐数,还原为默认
- #pragma pack(1)//设置默认对齐数为1
- struct S2
- {
- char c1;
- int i;
- char c2;
- };
- #pragma pack()//取消设置的默认对齐数,还原为默认
- int main()
- {
-
- //输出的结果是什么?
- printf("%d\n", sizeof(struct S1));
- printf("%d\n", sizeof(struct S2));
-
- return 0;
- }
运行结果:

