Lesson 0015 · C++ 进阶总复习 + 结课项目

C++ 进阶 — 第 8 课

三句话速览
  1. 12 课串一条线:语法 → STL → 对象 → 文件。
  2. 结课项目就是把这四块拼成一个程序。
  3. 写完能跑通、结果正确,这一阶段就毕业。
回顾:从 0003 的变量分支,到 0014 的文件读写,你已经学了 12 课。
这节课:不学新语法,用一个大项目把学过的东西全部串起来。做完它,C++ 进阶阶段就毕业了 🎓

1. 12 课都学了什么

课程核心一句话记忆点
0003 变量/分支/函数if/else、函数函数是「给一段代码起个名字」
0004 循环/数组for、数组重复做 + 按下标取
0005 string/vector动态数组push_back 随便加,不用管长度
0006 嵌套循环双重 for外层走一步,内层走一圈
0007 指针/引用& 和 *引用是别名,指针是地址
0008 STLsort/set/map别人写好的武器库
0009 struct/class打包数据和函数装进一个盒子
0010 递归自己调自己必须有出口,否则爆栈
0011 栈/队列/优先队列stack/queue/pq后进先出 / 先进先出 / 自动排序
0012 复杂度大 O估一估程序跑多快
0013 构造/析构出生和临终构造初始化,析构清理
0014 文件读写ofstream/ifstream数据存下来,下次还能用

这张表从下往上看,就是项目里代码的执行顺序:先读文件(0014)→ 用 struct 打包(0009)→ 存进 vector(0005)→ 循环算总分(0004)→ sort 排序(0008)→ 写回文件(0014)。

2. 自查清单

先别看代码,能不能答出来?

点开看答案

3. 坑点清单

4. 小测

Q1. 递归函数必须有什么?
Q2. 引用和指针的区别是?
Q3. map 遍历时默认按什么顺序输出?
Q4. 排序比较函数返回 true 表示什么?
Q5. while (in >> x) 什么时候停?

5. 动手练习:学生成绩管理系统

先自己写!参考答案放在本节最后,写完之后再对。

数据文件 students.txt(每行:姓名 语文 数学 英语):

Alice 95 87 92
Bob 78 90 85
Cindy 88 94 91
David 92 76 88
Eva 85 82 79

要求

知识点对照:struct 打包(0009)→ vector 存储(0005)→ ifstream 读 / ofstream 写(0014)→ sort + 比较函数(0008)→ 循环累加(0004)

写之前想三步

  1. struct 里要存哪些字段?总分放哪?
  2. 读文件的循环怎么写?
  3. 比较函数里「总分不同比总分,总分相同比名字」怎么写?

进阶挑战(可选)

卡住时的自查顺序

  1. 文件读得进来吗?先在 while 里打印一行,确认读到的名字和三科都对得上。
  2. 总分算对了吗?手动加一遍第一个人:95 + 87 + 92 是不是 274。
  3. 比较函数两条都写了吗?先只按总分排序跑一次,再加名字那条。
  4. 排序结果和预期对不上:把 v 排序前后各打印一遍,看是谁的位置错了。
  5. result.txt 打开看了吗?名次是不是从 1 开始、总和是不是五个人。
  6. 还不对:把 students.txt、代码、result.txt 一起贴过来。
参考答案(写完了再点开)
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

struct Student {
    string name;
    int ch, ma, en;
    int total;
};

bool cmp(const Student& a, const Student& b) {
    if (a.total != b.total) return a.total > b.total;   // 总分高的在前
    return a.name < b.name;                             // 同分按名字升序
}

int main() {
    ifstream in("students.txt");
    if (!in) { cerr << "打不开 students.txt" << endl; return 1; }

    vector<Student> v;
    Student s;
    while (in >> s.name >> s.ch >> s.ma >> s.en) {
        s.total = s.ch + s.ma + s.en;
        v.push_back(s);
    }
    if (v.empty()) { cerr << "没有数据" << endl; return 1; }

    sort(v.begin(), v.end(), cmp);

    ofstream out("result.txt");
    for (int i = 0; i < v.size(); i++) {
        out << i + 1 << " " << v[i].name << " " << v[i].total << endl;
    }
    cout << "已写入 result.txt" << endl;
    return 0;
}

预期 result.txt:

1 Alice 274
2 Cindy 273
3 David 256
4 Bob 253
5 Eva 246

对一下数字:Alice 95+87+92=274,Cindy 88+94+91=273 —— 前两名只差 1 分,所以「同分按名字」那条规则在这份数据里其实用不上,但换个文件就可能用上,仍然要写。

本课小结

下一课预告
0301 面向对象:封装 —— 进阶阶段结束,下一阶段正式进入面向对象:class 不再只是「打包数据」,而是用 private / public 控制谁能碰、谁不能碰。
这门课继续只留一个成员函数、一个可访问接口的写法,把你在 0009、0013 学的东西往下推一层。
接下来做什么?告诉老师你想先开 ②离散数学 还是 ③面向对象。或者先继续刷几道题(P1157 / P1706 还没收尾)。

← 上一课 · 课程对照表

视频 回顾薄弱集数 · 书籍 查漏补缺