C 结构体嵌套
更新时间:2026-08-26。本文是
languages/c/主题入门层第 46 篇(由原《数组、字符串与结构体》拆出)。现实数据往往是一层套一层:学生 → 班级 → 学校。C 里表达这种"包含"关系,就是结构体嵌套——结构体的成员本身是个结构体。
本文要回答的问题
- 结构体里能放结构体吗?怎么初始化?
- 多级访问怎么写?
- 嵌套后内存怎么算?
一、结构体成员可以是结构体
c
struct Date {
int year;
int month;
int day;
};
struct Student {
int id;
char name[32];
struct Date birthday; // 成员是另一个结构体
};访问和初始化:
c
struct Student s = {
1001,
"alice",
{2000, 5, 20} // 嵌套的花括号初始化 birthday
};
// 多级访问:一层一层点下去
printf("%d-%d-%d\n", s.birthday.year, s.birthday.month, s.birthday.day);
s.birthday.year = 2001; // 修改嵌套成员嵌套访问就是逐层点号:s.birthday.year 读作"s 的 birthday 的 year"。没有魔法,一层一层来。
二、指定初始化嵌套
c
struct Student s = {
.id = 1001,
.birthday = {.year = 2000, .month = 5, .day = 20}
};嵌套 + 指定初始化,写清楚每一层,顺序随意:
c
struct Student s = {
.birthday = {.day = 20, .year = 2000}, // 顺序随意
.name = "alice"
};三、含数组的结构体:一个真实案例
成绩管理,学生有多次考试成绩:
c
#define NUM_EXAMS 3
struct Student {
int id;
char name[32];
float scores[NUM_EXAMS]; // 数组成员
float avg;
};c
struct Student s = {1001, "alice", {92.0, 88.5, 95.0}};
s.avg = 0;
for (int i = 0; i < NUM_EXAMS; i++) {
s.avg += s.scores[i];
}
s.avg /= NUM_EXAMS;
printf("%.1f\n", s.avg); // 91.8数组是结构体的一部分:整个结构体赋值/传值时,数组成员跟着一起复制(这跟裸数组"不能整体赋值"不同——结构体里的数组会整体拷贝)。
四、嵌套结构体指针
嵌套成员也可以是指针(指向另一个结构体),常用于共享数据:
c
struct School {
char name[64];
struct Student *students; // 指向动态数组
int count;
};这种"结构体指针成员"让结构体能引用堆上的大块数据,是动态内存管理后常见的组织方式。
五、内存大小估算
c
struct Date { int year; int month; int day; }; // 3 × 4 = 12 字节
struct Student {
int id; // 4
char name[32]; // 32
struct Date birthday; // 12
};
printf("%zu\n", sizeof(struct Student)); // 可能 48+(对齐填充)粗略 = 成员相加,实际可能更大——因为对齐(编译器在成员间插填充字节,让每个成员地址对齐)。sizeof 总是准的;为什么有填充,见高手层结构体内存对齐。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 嵌套初始化花括号漏层 | 值错位 | 一层一层写清楚 |
忘 #define NUM_EXAMS | 魔法数字 | 常量定义 |
| 按成员相加估大小 | 偏小 | 用 sizeof |
| 嵌套太深 | 代码难读 | 拆成函数/层次结构 |
| 结构体里的数组比较 | 不能 == | 逐个元素比较 |
七、与本站主线衔接
一句话总结
结构体成员可以是结构体或数组,初始化用嵌套花括号({...} 包内层)、访问用逐层点号(s.birthday.year);结构体里带数组时整体拷贝;大小以 sizeof 为准(有对齐填充)——一层一层"打包",再复杂的数据也能组织成清晰类型。