在 C 语言的编程世界里,基础数据类型(int、char、float等)只能描述单一属性,而现实中的复杂对象(如学生、书籍、员工)往往包含多个不同类型的属性。为了解决这个问题,C 语言提供了结构体(struct) 这一自定义类型,它是 C 语言实现复杂数据管理的核心工具。
本文将带你系统学习结构体的类型定义、变量创建、初始化,并重点图解结构体的内存对齐规则,彻底搞懂结构体的内存占用问题。
一、结构体基础认知
1. 什么是结构体?
结构体是用户自定义的聚合数据类型,可以将多个不同类型的变量封装在一起,用来描述一个对象的多个属性。 比如描述一个学生:包含姓名(字符数组)、年龄(整型)、学号(字符数组)、成绩(浮点型),用结构体就能完美整合这些属性。
2. 结构体类型的定义
定义结构体的语法格式:
// 1. 标准定义方式
struct 结构体名
{
成员1类型 成员1名称;
成员2类型 成员2名称;
// … 任意多个成员
};
// 2. 简化定义(定义时直接创建变量)
struct 结构体名
{
成员列表;
} 变量名1, 变量名2;
实战示例:定义学生结构体
// 定义一个描述学生的结构体类型
struct Student
{
// 成员变量
char name[20]; // 姓名
int age; // 年龄
char id[15]; // 学号
float score; // 成绩
};
⚠️ 注意:定义结构体类型时,不会分配内存,只有创建结构体变量时才会分配内存。
二、结构体变量的创建与初始化
1. 创建结构体变量
有了结构体类型,就可以像使用int、char一样创建变量:
// 方法1:先定义类型,再创建变量
struct Student stu1;
// 方法2:定义类型的同时创建变量
struct Student
{
char name[20];
int age;
} stu2, stu3;
2. 结构体变量的初始化
初始化就是给结构体的成员变量赋初值,有两种常用方式:
(1)按顺序初始化
// 定义+初始化(顺序必须和成员定义一致)
struct Student stu = {"张三", 18, "2025001", 95.5};
(2)指定成员初始化(推荐,更灵活)
C99 标准支持,不用严格按照顺序,可读性更强:
struct Student stu = {
.name = "李四",
.age = 19,
.score = 88.0,
.id = "2025002"
};
3. 结构体成员的访问
访问结构体成员使用点操作符(.),如果是结构体指针,使用箭头操作符(->):
#include <stdio.h>
struct Student
{
char name[20];
int age;
};
int main()
{
struct Student stu = {"王五", 20};
// 访问并打印成员
printf("姓名:%s\\n", stu.name);
printf("年龄:%d\\n", stu.age);
// 结构体指针访问
struct Student* p = &stu;
printf("年龄:%d\\n", p->age);
return 0;
}
三、重点:结构体的内存对齐(图解详解)
这是结构体最核心、面试最常考的知识点! 我们先看一个现象:
struct S
{
char c; // 1字节
int i; // 4字节
};
int main()
{
// 你以为输出5?实际输出8!
printf("%zu\\n", sizeof(struct S));
return 0;
}
为什么1+4=5,最终大小却是8?这就是内存对齐在起作用。
1. 为什么需要内存对齐?
总结:空间换时间,是编译器的默认优化规则。
2. 内存对齐的核心规则
记住 3 条黄金规则,所有结构体内存计算都能搞定:
3. 图解内存对齐(实战案例)
案例 1:基础结构体
struct S
{
char c; // 1字节
int i; // 4字节
};
内存布局图解:
偏移量:0 1 2 3 4 5 6 7
┌──┬────────┬────────────┐
│c │ 填充 │ i │
└──┴────────┴────────────┘
- 规则 1:char c 放在偏移量 0 处,占用 1 字节;
- 规则 2:int i 占 4 字节,必须放在 4 的整数倍地址,因此偏移量 0~3 中,偏移量 1~3 填充 3 个字节;
- 规则 3:总大小 = 1 (填充) + 4 = 8,是最大成员int(4)的整数倍,符合要求。
最终大小:8 字节。
案例 2:调整成员顺序(大小会变!)
struct S2
{
char c1; // 1
char c2; // 1
int i; // 4
};
内存布局图解:
偏移量:0 1 2 3 4 5 6 7
┌──┬──┬────────┬────────────┐
│c1│c2│ 填充 │ i │
└──┴──┴────────┴────────────┘
- c1放 0,c2放 1(1 的整数倍);
- int i需要放 4 的整数倍,偏移量 2~3 填充;
- 总大小:8 字节。
案例 3:嵌套结构体
struct A
{
char a;
int b;
};
struct B
{
char c;
struct A s;
double d;
};
计算步骤:
- char c放 0;
- 嵌套struct A对齐到 4 的整数倍,偏移量 4 开始;
- double d对齐到 8 的整数倍;
4. 修改默认对齐数
编译器默认对齐数通常是 4/8,我们可以用#pragma pack(n)手动修改:
// 设置默认对齐数为2
#pragma pack(2)
struct S
{
char c;
int i;
};
// 恢复默认对齐
#pragma pack()
此时结构体大小变为6 字节。
四、补充:位段、共用体与结构体的区别
你代码中出现的位段、共用体(union) 是结构体的延伸,这里做简单区分:
五、总结
掌握结构体的定义、初始化和内存对齐,是编写高效 C 语言程序、应对面试的必备技能!建议大家手动计算几个结构体的内存大小,结合图解加深理解。



