前言
在阅读过程中有任何问题都可以发布到评论区,有价值的问题将会放到文章末尾Q&A之中!
什么叫结构体
在生活中,我们的书包内可以同时放入语文书、数学书、文具盒等等不同类型的物品。
这些物品的类型不同,但是都是属于你的学习用品。
在程序中,结构体的功能和书包相同,就是将相关但是不同的数据类型“打包”在一起。
为什么要“打包”数据
比如说在一个班级中,每个学生都有自己的姓名、学号、成绩等等不同的信息。
如果这些信息是相对独立的,那么就没办法通过学生的姓名查询到成绩,学号等等相关信息。
在代码中,我们也可以模拟一下这种情形。
1 2 3 4 5 6 7 8 9 10
| #include <iostream>
using namespace std;
int main(){ int id, sorce; string name; return 0; }
|
使用这种方法来定义的话,必须通过判断的形式来获取到相关联的信息,特别麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <iostream>
using namespace std;
int main(){ int id, sorce; string name; if(name == "A"){ id = 1; sorce = 98; } if(name == "B"){ id = 2; sorce = 89; } ...; return 0; }
|
什么叫联合体
联合体和结构体十分类似,同样也是可以同时定义多个不同类型的变量。
但是和结构体不同的是,结构体中的每个成员都有自己的内存空间,而联合体中的所有元素共用同一片内存空间。
类似于变形金刚,有汽车和汽车人两种形态,但是同一时间只会存在一种形态。
结构体
声明
结构体的声明是通过 struct 关键字来定义的。
具体定义方式如下。
1 2 3 4 5
| struct Student { string name; int age; double score; };
|
强调:struct 是创建一个新的数据类型,而不是创建变量。
在此处,Student 的作用和 int 的作用是相同的。
定义
那么,既然 Student 的作用和 int 的作用是相同的,该如何定义一个结构体变量呢?
很简单,就像我们定义一个整数类型变量,或者整数类型数组的方式即可。
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct Student { string name; int age; double score; };
int main(){ int a; int b[110]; Student st1; student st2[110]; return 0; }
|
访问
访问结构体内的元素时,需要用 . 来进行访问。
访问之后所有的操作和普通的数据类型基本相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| struct Student { string name; int age; double score; };
int main(){ Student st1; cin >> st1.name >> st1.age >> st1.score; Student st2[110]; for(int i = 0; i < 10; i ++ ){ cin >> st2[i].name >> st2[i].age >> st2[i].sorce; } Student st3 = {"abc", 18, 92.6}; cout << st1.name << " " << st1.age << " " << st1.score << endl; return 0; }
|
函数中的结构体
当结构体作为函数的参数进行传递的时候,同样也有传值参数和引用参数两种方式。
同样的,作为传值参数传递的时候在函数中修改结构体的变量的值不会影响到原结构体中的内容。
作为引用参数传递的时候在函数中修改结构体的变量的值会影响到原结构体中的内容。
值传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream>
using namespace std;
struct Student { string name; int age; double score; };
void printStudent(Student s) { cout << "姓名: " << s.name << endl; cout << "年龄: " << s.age << endl; cout << "成绩: " << s.score << endl; s.age = 20; }
int main() { Student st1 = {"张三", 18, 90.5}; printStudent(st1); cout << "实际年龄: " << st1.age << endl; return 0; }
|
引用传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream>
using namespace std;
struct Student { string name; int age; double score; };
void updateStudent(Student &s, double newScore) { s.score = newScore; cout << s.name << "的成绩已更新为: " << s.score << endl; }
int main() { Student st1 = {"李四", 17, 85.0}; updateStudent(st1, 92.5); cout << "更新后的成绩: " << st1.score << endl; return 0; }
|
嵌套
结构体同样也可以作为另外一个结构体中的成员,形成嵌套结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> using namespace std;
struct Date { int year; int month; int day; };
struct Address { string province; string city; string street; };
struct Student { string name; int age; double score; Date birthday; Address address; };
int main() { Student stu1 = { "张三", 18, 90.5, {2005, 5, 15}, {"A省", "B市", "C区"} }; cout << "学生信息:" << endl; cout << "姓名: " << stu1.name << endl; cout << "生日: " << stu1.birthday.year << "年" << stu1.birthday.month << "月" << stu1.birthday.day << "日" << endl; cout << "地址: " << stu1.address.province << stu1.address.city << stu1.address.street << endl; return 0; }
|
结构体排序
在程序设计中,我们经常需要对一组数据进行排序。
当这组数据是结构体时,排序就变得更加实用和有趣。
接下来将会讲解两种对结构体进行排序的方法:传统的冒泡排序和现代的STL sort函数。
为什么需要结构体排序?
在实际应用中,我们很少只对单一数据进行排序。比如学生管理系统,我们可能需要:
- 按成绩从高到低排名
- 按年龄从小到大排序
- 先按班级排序,再按成绩排序
- 按姓名拼音顺序排列
结构体排序让我们能够以多种方式组织和查看数据,满足不同的业务需求。
初始化结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <string> #include <algorithm> using namespace std;
struct Student { string name; int age; double score; void display() const { cout << name << "\t" << age << "\t" << score << endl; } };
|
方法一:冒泡排序 - 理解排序的本质
冒泡排序是最经典的排序算法之一,通过相邻元素的比较和交换来达到排序的目的。
基本原理
冒泡排序就像水中的气泡一样,较大的元素会逐渐”浮”到数组的顶端。它的核心思想是:
- 从第一个元素开始,比较相邻的两个元素
- 如果顺序不对,就交换它们
- 重复这个过程,直到整个数组有序
按成绩降序排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void bubbleSortByScore(Student arr[], int n) { for(int i = 0; i < n-1; i++) { for(int j = 0; j < n-i-1; j++) { if(arr[j].score < arr[j+1].score) { Student temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
|
代码解析:
- 外层循环控制排序的轮数
- 内层循环进行相邻元素的比较和交换
n-i-1 是因为每轮排序后,最后的元素已经是最大的了
按年龄升序排序
1 2 3 4 5 6 7 8 9 10 11 12 13
| void bubbleSortByAge(Student arr[], int n) { for(int i = 0; i < n-1; i++) { for(int j = 0; j < n-i-1; j++) { if(arr[j].age > arr[j+1].age) { Student temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
|
多级排序:更复杂的排序需求
在实际应用中,我们经常需要多级排序。比如先按成绩排序,成绩相同的再按年龄排序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void bubbleSortMultiLevel(Student arr[], int n) { for(int i = 0; i < n-1; i++) { for(int j = 0; j < n-i-1; j++) { if(arr[j].score < arr[j+1].score) { Student temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } else if(arr[j].score == arr[j+1].score && arr[j].age > arr[j+1].age) { Student temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
|
冒泡排序的完整示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void demonstrateBubbleSort() { Student students[5] = { {"张三", 18, 85.5}, {"李四", 17, 92.0}, {"王五", 19, 78.5}, {"赵六", 18, 88.0}, {"孙七", 17, 95.5} }; cout << "=== 冒泡排序演示 ===" << endl; cout << "排序前:" << endl; cout << "姓名\t年龄\t成绩" << endl; for(int i = 0; i < 5; i++) { students[i].display(); } bubbleSortMultiLevel(students, 5); cout << "\n排序后(成绩降序,成绩相同年龄升序):" << endl; cout << "姓名\t年龄\t成绩" << endl; for(int i = 0; i < 5; i++) { students[i].display(); } }
|
方法二:sort函数 - 现代C++的利器
STL 中的 sort函数是一个高效且灵活的排序工具,它采用了快速排序、堆排序和插入排序的混合算法。
使用比较函数
比较函数是告诉sort函数如何比较两个元素的关键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| bool compareByScore(const Student &a, const Student &b) { return a.score > b.score; }
bool compareByAge(const Student &a, const Student &b) { return a.age < b.age; }
bool compareMultiLevel(const Student &a, const Student &b) { if(a.score != b.score) return a.score > b.score; else return a.age < b.age; }
|
使用sort函数排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| void demonstrateSortFunction() { Student students[5] = { {"张三", 18, 85.5}, {"李四", 17, 92.0}, {"王五", 19, 78.5}, {"赵六", 18, 88.0}, {"孙七", 17, 95.5} }; cout << "=== STL sort函数演示 ===" << endl; sort(students, students + 5, compareByScore); cout << "按成绩降序:" << endl; cout << "姓名\t年龄\t成绩" << endl; for(int i = 0; i < 5; i++) students[i].display(); sort(students, students + 5, compareByAge); cout << "\n按年龄升序:" << endl; cout << "姓名\t年龄\t成绩" << endl; for(int i = 0; i < 5; i++) students[i].display(); sort(students, students + 5, compareMultiLevel); cout << "\n多级排序(成绩降序,成绩相同年龄升序):" << endl; cout << "姓名\t年龄\t成绩" << endl; for(int i = 0; i < 5; i++) students[i].display(); }
|
联合体
联合体(union)是C++中一种特殊的数据类型,它允许在同一块内存空间中存储不同的数据类型。
联合体的所有成员共享同一块内存,这意味着同一时间只能有一个成员是有效的。
声明、定义和访问
联合体的声明、定义和访问的方式和结构体是完全相同的。
只不过在访问的过程中,后访问的元素会覆盖掉先访问到的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> using namespace std;
union Data { int i; double d; char c; };
int main() { Data data; data.i = 10; cout << "整数: " << data.i << endl; data.d = 3.14; cout << "浮点数: " << data.d << endl; data.c = 'A'; cout << "字符: " << data.c << endl; return 0; }
|
对比
| 特性 |
结构体 (struct) |
联合体 (union) |
| 关键字 |
struct |
union |
| 内存分配 |
每个成员有独立内存空间 |
所有成员共享同一块内存 |
| 内存大小 |
≥ 所有成员大小之和(内存对齐) |
= 最大成员的大小 |
| 成员使用 |
所有成员可以同时使用和访问 |
同一时间只能有一个成员有效 |
| 数据安全 |
成员相互独立,不会意外覆盖 |
可能因错误使用导致数据覆盖 |
| 初始化 |
可以同时初始化所有成员 |
只能初始化第一个成员 |
| 访问方式 |
使用点运算符.访问成员 |
使用点运算符.访问成员 |
| 比喻 |
书包 - 可同时放书、笔、本子 |
变形金刚 - 同一时间只能是一种形态 |
| 适用场景 |
数据记录、对象建模、需要同时使用多个数据 |
节省内存、类型转换、硬件编程、数据互斥 |
使用技巧
typedef 简化
什么是typedef?
typedef 是C++中的关键字,用于为已有的数据类型创建新的名称(别名)。就像给人起外号一样,让复杂的名字变得简单好记。
基本语法
简化结构体类型名
传统方式的问题
1 2 3 4 5 6 7 8
| struct Student { string name; int age; };
struct Student stu1; struct Student students[100];
|
使用typedef简化
1 2 3 4 5 6 7 8 9 10 11 12
| struct Student { string name; int age; double score; };
typedef struct Student Stu;
Stu stu1; Stu students[100];
|
更简洁的定义方式
1 2 3 4 5 6 7 8 9 10
| typedef struct Student { string name; int age; double score; } Stu;
Stu stu1; stu1.name = "李四";
|
最简洁的方式(匿名结构体)
1 2 3 4 5 6 7 8 9 10
| typedef struct { string name; int age; double score; } Stu;
Stu stu1; Stu class1[50];
|
Q&A