11. 结构体与共用体:把数据组织起来
说实话,C++ 里最让我觉得「贴心」的设计之一,就是结构体。为什么?因为现实世界里的数据,很少是孤零零的。比如一个学生,有姓名、年龄、成绩——这三样东西你总不能各管各的吧?结构体就是用来干这个的:把相关的数据打包成一个整体。
今天我们就来聊聊结构体和它的「表兄弟」共用体。我会结合我这些年踩过的坑,给你讲明白。
11.1 结构体的定义与使用
结构体,说白了就是自定义的数据类型。你可以把不同类型的数据组合在一起。
// 定义一个学生结构体
struct Student {
char name[20];
int age;
float score;
};
int main() {
// 声明一个结构体变量
Student stu1;
// 访问成员
strcpy(stu1.name, "张三");
stu1.age = 20;
stu1.score = 89.5;
// 也可以直接初始化
Student stu2 = {"李四", 22, 95.0};
return 0;
}
我个人习惯在定义结构体时,把成员变量按「从大到小」的顺序排列。为什么?因为内存对齐。嗯,这个后面会细说。
11.2 结构体数组
一个学生好办,一群学生呢?用数组呗。结构体数组就是每个元素都是一个结构体。
// 定义一个班级,最多 50 人
Student class1[50];
// 初始化部分学生
Student class2[3] = {
{"王五", 19, 88.0},
{"赵六", 20, 92.5},
{"孙七", 21, 76.0}
};
// 遍历访问
for (int i = 0; i < 3; i++) {
cout << class2[i].name << " " << class2[i].score << endl;
}
我在项目中遇到过一个问题:用结构体数组存传感器数据,结果数组越界了。嗯,C++ 不检查数组边界,你得自己小心。我建议用 std::vector 代替原生数组,安全得多。
11.3 结构体指针
结构体指针,就是指向结构体的指针。用指针操作结构体,效率更高,尤其是传参的时候。
Student stu = {"小明", 18, 90.0};
Student* pStu = &stu;
// 两种访问方式
cout << (*pStu).name << endl; // 先解引用,再访问
cout << pStu->name << endl; // 用 -> 更直观
你想想看,如果结构体很大,每次传参都复制一份,多浪费内存。用指针传地址,就快多了。
11.4 位域
位域,这是个有意思的东西。它让你可以精确控制每个成员占几个二进制位。说白了,就是省内存。
struct Flags {
unsigned int isReady : 1; // 只占 1 位
unsigned int isError : 1; // 只占 1 位
unsigned int mode : 2; // 占 2 位,可以表示 0~3
unsigned int count : 4; // 占 4 位,可以表示 0~15
};
int main() {
Flags f = {1, 0, 2, 10};
cout << f.isReady << " " << f.mode << endl;
return 0;
}
位域在嵌入式开发里特别常见。比如你要跟硬件寄存器打交道,每个位都有特定含义。我当年做通信协议时,就用位域来解析数据包头部,省了不少功夫。
11.5 共用体
共用体,英文叫 union。它和结构体很像,但有一个关键区别:所有成员共享同一块内存。
union Data {
int i;
float f;
char str[4];
};
int main() {
Data d;
d.i = 42;
cout << d.i << endl; // 输出 42
d.f = 3.14;
cout << d.f << endl; // 输出 3.14
// 注意:此时 d.i 的值已经被覆盖了
return 0;
}
为什么会这样?因为共用体里所有成员都从同一个地址开始存储。你给一个成员赋值,其他成员的值就变了。共用体的大小,等于最大成员的大小。
我建议你在以下场景用共用体:
- 需要节省内存,且同一时刻只用到一个成员
- 做数据类型的转换(比如把 float 的字节拆开看)
- 解析网络协议或文件格式时
11.6 结构体与共用体的对比
| 特性 | 结构体 (struct) | 共用体 (union) |
|---|---|---|
| 内存分配 | 每个成员独立分配 | 所有成员共享同一块内存 |
| 总大小 | 所有成员大小之和(考虑对齐) | 最大成员的大小 |
| 同时使用 | 所有成员可同时使用 | 同一时刻只能用一个成员 |
| 典型用途 | 组织相关数据 | 节省内存、类型转换 |
11.7 知识体系图
下面这张图帮你理清结构体和共用体的核心脉络:
这张图把今天的内容串起来了。结构体和共用体是两种不同的数据组织方式,位域则是结构体里的一个特殊功能。你掌握了这些,C++ 的数据管理能力就上了一个台阶。
公众号:蓝海资料掘金营,微信deep3321