在 C++ 中,结构体(struct) 是一种用户自定义的数据类型,可以将不同类型的数据组合在一起。
结构体提供了一种方便的方法来处理与现实实体相关的数据,例如学生、书籍、坐标点等。结构体可以包含成员变量(数据) 和成员函数(方法),虽然与类(class)类似,但结构体通常主要用于简单的数据聚合,并且在竞赛中我们通常不会使用成员函数。
结构体的定义使用 struct 关键字,后跟结构体的名称和一组包含在大括号 {} 中的成员变量,以分号结尾。
定义结构体时需要注意以下几点:
下面分别展示定义只包含基础数据类型、包含数组、以及包含结构体数组的结构体:
1#include <iostream>
2using namespace std;
3
4struct Person{
5 string name; // 姓名
6 int age; // 年龄
7 double height; // 身高
8 double weight; // 体重
9};1#include <iostream>
2using namespace std;
3
4struct Transcript{
5 string class_id; // 班级编号
6 int scores[100]; // 成绩数组
7};1#include <iostream>
2using namespace std;
3
4struct Person{
5 string name; // 姓名
6 int age; // 年龄
7 double height; // 身高
8 double weight; // 体重
9};
10
11struct Group{
12 int group_id;
13 Person persons[100];
14};结构体是一种自定义的数据类型,因此我们需要把结构体当做数据类型来使用即可。获取结构体变量中的成员变量时,需要使用 . 运算符。
使用自定义的结构体定义变量与定义基础数据类型的变量没有区别,仅需要将基础数据类型的关键字改为自定义的结构体名称即可。
下面展示两种定义和初始化结构体变量的方式:
1#include <iostream>
2using namespace std;
3
4struct Point {
5 int x;
6 int y;
7};
8
9int main() {
10 // 定义Point类型的变量p1,使用.的方式对其进行赋值。
11 Point p1;
12 p1.x = 3;
13 p1.y = 6;
14
15 // 定义Point类型的变量p2,使用初始化列表的方式对其成员变量进行初始化
16 // 此方法需要注意:仅可以对基础数据类型的成员变量进行初始化
17 Point p2 = {10, 20}; // 列表初始化
18
19 cout << "Point p1: (" << p1.x << ", " << p1.y << ")" << endl;
20 cout << "Point p2: (" << p2.x << ", " << p2.y << ")" << endl;
21
22 return 0;
23}1#include <iostream>
2using namespace std;
3
4// 定义Point类型结构体
5// 定义Point类型的变量p1,不对p1进行初始化
6// 定义Point类型的变量p2,使用列表的方式对p2进行初始化
7// 在此处定义的p1和p2是全局变量
8struct Point {
9 int x;
10 int y;
11}p1, p2{4, 8};
12
13int main() {
14 // 主函数内可以直接使用p1和p2
15 p1.x = 3;
16 p1.y = 6;
17
18 cout << "Point p1: (" << p1.x << ", " << p1.y << ")" << endl;
19 cout << "Point p2: (" << p2.x << ", " << p2.y << ")" << endl;
20
21 return 0;
22}使用自定义的结构体定义数组与定义基础数据类型的数组没有区别,仅需要将基础数据类型的关键字改为自定义的结构体名称即可。
1#include <iostream>
2using namespace std;
3
4struct Point {
5 int x;
6 int y;
7};
8
9// 定义Point类型的数组p
10Point p[1000];
11
12int main() {
13 // 对结构体数组p进行赋值
14 for (int i = 0; i < 1000; ++i) {
15 p[i].x = i;
16 p[i].y = i;
17 }
18
19 return 0;
20}可以把自定义结构体类型的变量当做参数传递给函数,也可以让一个函数返回一个自定义结构体类型的数据。
1#include <iostream>
2using namespace std;
3
4struct Point {
5 int x;
6 int y;
7};
8
9// 输出一个Point类型的变量的成员变量
10void printPoint(Point p) {
11 cout << "Point: (" << p.x << ", " << p.y << ")" << endl;
12}
13
14// 创建一个Point类型的变量
15Point createPoint(int x, int y) {
16 Point p;
17 p.x = x;
18 p.y = y;
19 return p;
20}
21
22int main() {
23 Point p1 = createPoint(10, 20);
24 printPoint(p1);
25
26 return 0;
27}在 C++ 中,联合体(union) 是一种用户自定义的数据类型,类似于结构体(struct),但具有不同的内存管理方式。联合体中的所有成员共享同一块内存,意味着在任一时刻,联合体只能存储其中一个成员的值。联合体主要用于需要高效地使用内存的场景。
联合体通常用于以下场景:
联合体的定义使用 union 关键字,后跟联合体的名称和一组包含在大括号 {} 中的成员变量,以分号结尾。
定义联合体时需要注意以下几点:
1#include <iostream>
2using namespace std;
3
4union Data {
5 int i;
6 float f;
7 char c;
8};
9
10int main() {
11 Data data;
12
13 data.i = 10;
14 cout << "data.i: " << data.i << endl;
15
16 data.f = 3.14;
17 cout << "data.f: " << data.f << endl;
18
19 data.c = 'a';
20 cout << "data.c: " << data.c << endl;
21
22 // 注意:此时访问其他成员将得到未定义的结果
23 cout << "data.i: " << data.i << endl;
24
25 return 0;
26}联合体的使用方式和结构体基本一致,可以使用初始化列表对联合体变量进行初始化。
1#include <iostream>
2using namespace std;
3
4union Data {
5 int i;
6 float f;
7 char c;
8};
9
10int main() {
11 Data data = {10}; // 初始化整数成员
12
13 cout << "data.i: " << data.i << endl;
14
15 data = {3.14f}; // 初始化浮点数成员
16 cout << "data.f: " << data.f << endl;
17
18 data = {'a'}; // 初始化字符成员
19 cout << "data.c: " << data.c << endl;
20
21 return 0;
22}在某些情况下,联合体可以是匿名的,即没有名称的联合体。匿名联合体的成员直接属于包含它的作用域,可以在结构体内部使用。
1#include <iostream>
2using namespace std;
3
4struct Test {
5 union {
6 int i;
7 float f;
8 };
9
10 void print() {
11 cout << "i: " << i << ", f: " << f << endl;
12 }
13};
14
15int main() {
16 Test t;
17 t.i = 10;
18 t.print();
19
20 t.f = 3.14f;
21 t.print();
22
23 return 0;
24}下面通过具体的内存示意图,展示结构体和联合体的工作方式。
例1:结构体的内存布局
1struct Student {
2 char name[10]; // 占10字节
3 int age; // 占4字节
4 double score; // 占8字节
5};
6
7Student s = {"Tom", 15, 92.5};结构体各成员在内存中依次排列,每个成员拥有独立的存储空间:
1内存地址(示意):
2+----------+------+----------+
3| name | age | score |
4| "Tom" | 15 | 92.5 |
5| [10字节] |[4字节]| [8字节] |
6+----------+------+----------+结构体的总大小 >= 所有成员大小之和(实际可能因内存对齐而更大)。
例2:联合体的内存布局
1union Data {
2 int i; // 占4字节
3 float f; // 占4字节
4 char c; // 占1字节
5};
6
7Data d;联合体所有成员共享同一块内存,大小等于最大成员的大小:
内存地址(示意):
+----------------+
| i / f / c |
| 共享 [4字节] |
+----------------+d.i = 10; → 内存中存储整数10
d.f = 3.14; → 内存被覆盖为浮点数3.14,此时d.i的值已经无意义
d.c = 'A'; → 内存被覆盖为字符'A',此时d.i和d.f的值已经无意义例3:结构体数组的定义、赋值与排序
1struct Student {
2 string name;
3 int score;
4};
5
6Student stu[3];
7
8// 读入3个学生信息
9for (int i = 0; i < 3; ++i) {
10 cin >> stu[i].name >> stu[i].score;
11}假设输入为 Alice 85、Bob 92、Charlie 78,内存中的存储状态:
stu[0]: name="Alice", score=85
stu[1]: name="Bob", score=92
stu[2]: name="Charlie", score=78配合 sort 按成绩降序排序后:
stu[0]: name="Bob", score=92
stu[1]: name="Alice", score=85
stu[2]: name="Charlie", score=78使用结构体解决编程问题的一般步骤:
struct 定义结构体,包含所有需要的成员变量. 运算符逐个读入每个结构体的成员变量. 运算符访问成员变量并输出典型应用场景示例——按要求排序学生信息:
1#include <bits/stdc++.h>
2using namespace std;
3
4struct Student {
5 string name;
6 int score;
7};
8
9bool cmp(Student a, Student b) {
10 return a.score > b.score; // 按成绩降序排列
11}
12
13Student stu[1005];
14
15int main() {
16 int n;
17 cin >> n;
18 for (int i = 0; i < n; ++i) {
19 cin >> stu[i].name >> stu[i].score;
20 }
21 sort(stu, stu + n, cmp);
22 for (int i = 0; i < n; ++i) {
23 cout << stu[i].name << " " << stu[i].score << endl;
24 }
25 return 0;
26}struct Point { int x; int y; } 后面必须加 ;,否则编译报错. 和 ->:使用结构体变量访问成员用 .(如 stu.name),使用结构体指针访问成员用 ->(如 ptr->name)。在本阶段主要使用 . 运算符使用联合体时需要特别注意以下两点:
