固定数组
array<int, 5> scores{};
大小编译时确定,适合数量永远固定的小集合,并提供 size 和范围循环。
Easy explanation
普通数组的柜子数量在创建时固定,vector 能在需要时扩建,并记录自己当前有多少元素。我们可以从尾部加入、按位置读取,也可以遍历所有柜子。扩建可能把整排柜子搬到新位置,因此保存旧元素地址或迭代器时要格外小心。
容器只负责存放数据,程序仍要决定如何查找、修改和删除。处理列表时先明确元素类型、唯一标识和允许操作。例如学生记录用学号作为唯一标识,比用可能重复的姓名更可靠。
Core concepts
array<int, 5> scores{};
大小编译时确定,适合数量永远固定的小集合,并提供 size 和范围循环。
vector<Student> students;
元素数量运行时变化,push_back 添加,size 返回数量,empty 判断是否为空。
values.at(index)
at 会检查范围,下标来自用户时优先使用。方括号更快但越界不会自动保护。
for (auto it = v.begin(); it != v.end(); ++it)
迭代器表示容器中的位置,许多 STL 算法用一对迭代器描述处理范围。
values.push_back(42);在尾部添加一个元素,容器大小自动增加。
for (const auto& item : items)只读遍历对象时用 const 引用,避免复制。
v.erase(v.begin() + index);按位置删除后,后面的元素会向前移动,旧下标随之变化。
vector<vector<int>> grid(rows, vector<int>(cols));二维 vector 可以表示座位表、地图或成绩矩阵。
Complete examples
Example 1
每个 Student 同时保存学号、姓名和分数。查找函数返回指针,找到时指向 vector 中的对象,找不到返回 nullptr。
修改前先验证新分数,避免把非法数据写入对象。真实项目还要保证学号唯一。
struct Student { int id; string name; int score; };
Student* findById(vector<Student>& students, int id)
{
for (Student& student : students)
if (student.id == id) return &student;
return nullptr;
}
vector<Student> students{{101, "Mia", 88}, {102, "Tom", 76}};
students.push_back({103, "Lina", 95});
if (Student* found = findById(students, 102))
found->score = 82;
for (const Student& s : students)
cout << s.id << ' ' << s.name << ' ' << s.score << '\n';
Example 2
remove_if 不会直接缩短 vector,而是把保留元素移动到前面并返回新的逻辑结尾。erase 再真正删除尾部区域。
谓词函数接收一个元素并返回是否删除。把条件写成 lambda 能让规则紧挨操作位置。
students.erase(
remove_if(students.begin(), students.end(),
[](const Student& student)
{
return student.score < 60;
}),
students.end());
cout << "剩余人数:" << students.size() << '\n';
Algorithm thinking
好的容器设计从元素类型开始。若三个 vector 分别保存姓名、学号和成绩,很容易长度不同步;把三项组合成 Student,再使用 vector<Student>,一条记录始终保持完整。
顺序查找从头看到尾,最多检查 n 个元素,简单且适合小列表。删除中间元素会移动后续内容,因此循环删除时要小心下标变化。优先使用标准算法或正确更新迭代器。
把属于同一条记录的数据放进 struct 或 class。
选择学号、编号等稳定键,不依赖可能重复或变化的显示名称。
先完成查找,再在查找结果上实现修改和删除。
覆盖空列表、一个元素、首尾元素和找不到目标。
Common mistakes
合法下标最大是 size()-1,空 vector 时不能计算最后下标。
erase 会让后续迭代器失效,必须使用返回的新迭代器或标准算法。
范围循环写 auto item 会复制,修改或只读大对象时应使用引用。
push_back 触发扩容后,之前指向元素的指针可能失效。不要长期保存。
先准备一个最小输入,只保留能够重现问题的几行数据;再在关键步骤输出变量值,确认程序究竟在哪一步偏离预期。编译错误从第一条开始处理,运行错误则比较“实际结果”和“期望结果”。修复后别只重跑原来的例子,还要增加空输入、边界值和错误输入,防止问题换一个形式再次出现。
Homework
建议按顺序完成。前四题帮助巩固语法和基本操作,第五到第七题要求把多个知识点组合起来,第八题是小项目。每道题都要先写输入、处理、输出三行计划,再开始敲代码;程序运行后至少测试正常情况、边界情况和错误情况。
读取任意个整数,输出总和、平均值、最大值和所有大于平均值的元素。
分别用下标和反向迭代器倒序输出 vector,比较两种写法。
不使用 set,把输入列表中的重复值删除并保留第一次出现顺序。
按学号查找、修改和删除学生,找不到时不能误改其他记录。
使用二维 vector 表示座位,支持预订、取消、打印和剩余座位统计。
商品包含编号、名称、价格和库存,实现进货、购买与低库存筛选。
支持尾部添加、按位置插入、删除指定歌曲和移动歌曲顺序。
完成增删改查、平均分、最高分和等级人数统计,所有操作通过菜单执行。
本课验收标准:能解释 array 与 vector 的选择;增删改查覆盖空列表和找不到目标;遍历对象时正确使用引用;不发生下标越界或删除导致的迭代器错误。
提交内容应包括源代码、三组测试输入与输出、一个曾经出现的错误及修复方法。最后请用自己的话解释本课最重要的概念;如果只能照着代码念,还需要再独立重写一次核心例子。