vector、循环遍历、累加、找最大值全部用进一个完整程序:
先输入班级人数,再逐个录入成绩,最后输出总分、平均分、最高分。
vector、循环遍历、累加、找最大值全部用进一个完整程序:
先输入班级人数,再逐个录入成绩,最后输出总分、平均分、最高分。
第 14 讲:数组,用下标集中管理一批数据,但长度声明后就定死了。
第 15 讲:循环 + 数组,用循环变量当下标遍历、求和、打擂台找最大值。
第 16 讲:vector,不用提前定长,push_back
随时加、.size() 随时知道有多少个。
第 17 讲:字符串其实也遵循同一套下标、遍历规则。
今天把 vector、遍历、求和、找最大值拼在一起,做一个真正有用的小工具。
vector 存起来,成绩范围是 0~100。
班级人数运行时才知道,用数组不合适——这正是第 16 讲学 vector
的原因。第一步先只做“录入 + 原样打印回顾”,确认这部分没问题,再往上加统计功能:
#include <cstddef>
#include <iostream>
#include <vector>
int main() {
int n;
std::cout << "这个班有多少人?";
if (!(std::cin >> n) || n <= 0) {
std::cout << "人数必须是正整数。" << std::endl;
return 1;
}
std::vector<int> scores;
for (int i = 0; i < n; i++) {
int s;
std::cout << "请输入第 " << (i + 1) << " 个人的分数:";
if (!(std::cin >> s) || s < 0 || s > 100) {
std::cout << "成绩必须是 0 到 100 之间的整数。" << std::endl;
return 1;
}
scores.push_back(s);
}
std::cout << "录入完毕,一共 " << scores.size() << " 个分数:" << std::endl;
for (int score : scores) {
std::cout << score << " ";
}
std::cout << std::endl;
return 0;
} vector。
这里保存全部成绩,是为了练习本模块的容器与遍历,也方便原样打印、反复统计,
以及完成后面的“输出所有高于平均分的成绩”等二次分析。
std::cin >> n 可以直接放进 if 条件:
读取成功时条件成立,输入字母或遇到文件结束时条件失败。
程序还会检查人数必须大于 0、成绩必须在 0~100,
从源头保证后面的平均分和 scores[0] 都有意义。
把 roster_step1.cpp 跑起来,输入人数为 3,再输入 3 个分数,
确认最后打印出来的和你输入的一致。
有了装满数据的 scores,求和就是熟悉的累加器遍历,循环条件用
.size() 而不是写死的数字:
int sum = 0;
for (int score : scores) {
sum += score;
}
double average = sum / static_cast<double>(scores.size());
std::cout << "总分:" << sum << std::endl;
std::cout << "平均分:" << average << std::endl; scores.size() 返回的类型不是普通 int,直接用
sum / scores.size() 容易踩到“整数除法截断小数”的坑。
static_cast<double>(scores.size())
会先把人数明确转换成 double 再参与除法,确保平均分带小数。
它比 C 风格的 (double) 写法更清楚,也更符合现代 C++ 的习惯。
第 15 讲的打擂台算法,数据结构从数组换成 vector,
代码几乎不用改:
int maxScore = scores[0];
for (std::size_t i = 1; i < scores.size(); i++) {
if (scores[i] > maxScore) {
maxScore = scores[i];
}
}
std::cout << "最高分:" << maxScore << std::endl; #include <cstddef>
#include <iostream>
#include <vector>
int main() {
int n;
std::cout << "这个班有多少人?";
if (!(std::cin >> n) || n <= 0) {
std::cout << "人数必须是正整数。" << std::endl;
return 1;
}
std::vector<int> scores;
for (int i = 0; i < n; i++) {
int s;
std::cout << "请输入第 " << (i + 1) << " 个人的分数:";
if (!(std::cin >> s) || s < 0 || s > 100) {
std::cout << "成绩必须是 0 到 100 之间的整数。" << std::endl;
return 1;
}
scores.push_back(s);
}
int sum = 0;
for (int score : scores) {
sum += score;
}
double average = sum / static_cast<double>(scores.size());
int maxScore = scores[0];
for (std::size_t i = 1; i < scores.size(); i++) {
if (scores[i] > maxScore) {
maxScore = scores[i];
}
}
std::cout << "----------------------" << std::endl;
std::cout << "总分:" << sum << std::endl;
std::cout << "平均分:" << average << std::endl;
std::cout << "最高分:" << maxScore << std::endl;
return 0;
}
整个程序只用了一个 vector 存所有成绩,之后的求和、
求平均、找最高分,全都基于这一份数据反复遍历——录入一次,统计三次。
三段统计代码是相互独立的:删掉找最高分那一段,求和平均分照样能跑, 这也是分步骤搭建的好处——每一步都能单独验证。
跑起来,依次测试下面的场景,确认结果正确:
| 场景 | 期望表现 |
|---|---|
| 人数为 1,输入一个分数 | 总分、平均分、最高分都等于这个分数 |
| 人数为 5,分数各不相同 | 最高分是其中最大的那个 |
| 人数为 5,全部输入同一个分数 | 最高分等于这个分数,平均分也等于它 |
| 人数为 0、负数或字母 | 提示“人数必须是正整数”,安全结束 |
| 成绩为 -1、101 或字母 | 提示合法范围是 0 到 100,安全结束 |
| 有多个并列最高分 | 最高分数值仍然正确 |
scores[0] 是否安全。
仿照找最高分的打擂台算法,再加一段找最低分并输出。
遍历 scores,统计并输出及格(大于等于 60 分)的人数。
提示:需要一个计数器变量,遍历时符合条件就加一,回忆第 9 讲累加的写法。
算出平均分后,再遍历一次 scores,把所有高于平均分的成绩打印出来。
提示:这需要两轮遍历——第一轮算出平均分,第二轮才能拿平均分去比较, 顺序不能颠倒。
另写一个版本,不保存全部成绩:每读入一个成绩,就更新总分和最高分, 最后再计算平均分。比较两个版本,说明为什么这个版本不能在统计结束后 再打印所有高于平均分的原始成绩。
| 讲次 | 核心内容 |
|---|---|
| 第 14 讲 | 数组声明、下标从 0 开始、读写元素 |
| 第 15 讲 | 循环遍历数组、求和平均分、打擂台找最大 / 最小值 |
| 第 16 讲 | vector、push_back、.size() |
| 第 17 讲 | 字符串的 .length()、下标、遍历 |
| 第 18 讲 | 综合实战:vector + 遍历统计 |
到这里,程序已经能批量存储数据、批量处理数据—— 这是写“真正有用”的程序离不开的能力。
vector 里
(比如姓名和分数各存各的)。模块六学 struct,
把姓名、分数这些相关数据打包成一个整体,再综合前五个模块的内容,
完成两个综合项目。