次数明确的循环
for (int i = 0; i < n; ++i)
知道要重复多少次时优先使用 for。初始化、继续条件和更新集中在同一行,结构清楚。
Easy explanation
如果只有三名学生,复制三次输入代码似乎也能工作;但人数变成三十或三百,复制就会失控。循环的价值不是少打几行字,而是让同一套规则能够处理数量变化的数据。程序只需要知道什么时候开始、什么时候结束,以及每一轮要更新什么。
循环最常搭配几个“小记账本”:sum 保存总和,count 保存有效数量,maximum 保存目前见过的最大值。每读到一个新数据,就更新相关记账本。循环结束后,这些变量就是对整批数据的总结。理解这种逐步更新的思想,后面学习许多算法都会更轻松。
Core concepts
for (int i = 0; i < n; ++i)
知道要重复多少次时优先使用 for。初始化、继续条件和更新集中在同一行,结构清楚。
while (command != "quit")
不知道重复次数、只知道结束条件时使用 while,例如菜单、猜数字或读取到结束标记。
sum += value; ++count;
每轮用新数据更新当前答案。变量初值必须与含义一致,总和和数量通常从零开始。
break; / continue;
break 结束整个循环,continue 跳过本轮剩余部分。它们应让流程更清楚,而不是隐藏混乱条件。
for (int i = 1; i <= 10; ++i)从 1 到 10 包含两端;先在纸上写出第一轮和最后一轮。
double average = sum / count;计算前要确认 count 不为零,并注意整数除法问题。
if (value > maximum) maximum = value;新值只有更大时才替换目前最大值。
if (value < 0) continue;过滤无效数据后,本轮不再参与后续统计。
Complete examples
Example 1
用户输入 -1 表示结束,因此事先不知道有多少个成绩,适合 while。每个合法分数同时更新总分、人数、最高分和及格人数。
最高分不能随便初始化为零,因为别的问题可能允许负数。这里成绩范围保证不小于零,因此零可用;更通用的做法是用第一个有效值初始化。
int sum = 0, count = 0, passed = 0;
int highest = 0;
while (true)
{
cout << "输入成绩(-1 结束):";
int score;
cin >> score;
if (score == -1) break;
if (score < 0 || score > 100)
{
cout << "成绩无效\n";
continue;
}
sum += score;
++count;
if (score >= 60) ++passed;
if (score > highest) highest = score;
}
if (count > 0)
{
cout << "平均分:" << static_cast<double>(sum) / count << '\n';
cout << "最高分:" << highest << '\n';
cout << "及格人数:" << passed << '\n';
}
Example 2
质数只有 1 和自身两个正因数。最直接的方法从 2 检查到 n-1,但因数总是成对出现,只要检查到平方根就足够。
循环条件 i * i <= n 避免调用平方根函数。发现一个因数后立即 break,因为答案已经确定,继续检查没有意义。
bool isPrime = n >= 2;
for (int i = 2; i * i <= n && isPrime; ++i)
{
if (n % i == 0)
isPrime = false;
}
if (isPrime)
cout << n << " 是质数\n";
else
cout << n << " 不是质数\n";
Algorithm thinking
循环出错通常不是语法问题,而是变量含义不清。i 是已经处理的数量,还是当前下标?count 是全部输入,还是合法输入?在变量旁写一句含义,再检查初值、继续条件和更新是否与含义一致。这样能系统地发现少一次或多一次的错误。
设计算法时要找出每一轮保持不变的规则。例如处理完前 k 个成绩后,sum 必须等于这 k 个成绩的总和,maximum 必须是其中最大值。下一轮加入一个成绩,只需更新这些结果。这个思想叫循环不变量,是理解排序、查找和动态算法的重要基础。
明确一轮处理一个数字、一个字符、一个学生还是一整行命令。
使用固定次数、结束标记、用户命令或达到目标作为停止条件。
在循环前初始化总和、数量、当前最佳值或状态。
手动模拟空输入、一次输入和最后一个边界,确认没有多做或漏做。
Common mistakes
条件永远为真或忘记更新控制变量。每轮结束前检查什么发生了变化。
混淆 < 与 <=。把预期下标写在纸上,尤其检查第一项和最后一项。
sum 和 count 都是 int 时会丢掉小数,除法前把一边转换为 double。
用户立即结束时 count 为零,计算平均值之前必须单独处理。
先准备一个最小输入,只保留能够重现问题的几行数据;再在关键步骤输出变量值,确认程序究竟在哪一步偏离预期。编译错误从第一条开始处理,运行错误则比较“实际结果”和“期望结果”。修复后别只重跑原来的例子,还要增加空输入、边界值和错误输入,防止问题换一个形式再次出现。
Homework
建议按顺序完成。前四题帮助巩固语法和基本操作,第五到第七题要求把多个知识点组合起来,第八题是小项目。每道题都要先写输入、处理、输出三行计划,再开始敲代码;程序运行后至少测试正常情况、边界情况和错误情况。
输入起点和终点,计算闭区间所有整数之和,同时处理起点大于终点的情况。
用嵌套循环打印 1 到 9 的乘法表,对齐每一列,并解释内外层循环各控制什么。
用 while 依次取出正整数的每一位,计算位数、各位和以及反转后的数字。
输出 2 到 200 的所有质数,并统计一共找到多少个。复用本课质数判断思路。
输入本金、月利率和目标金额,计算至少需要几个月达到目标,防止无效利率造成无限循环。
统计平均分、最高最低分、及格率和每个等级人数,输入 -1 结束。
用嵌套循环输出左三角、右三角和空心矩形,尺寸由用户输入。
随机生成答案,提示太大或太小,限制次数,记录本局用时,并允许连续开始新游戏。
本课验收标准:能说明为什么选择 for 或 while;循环能正确处理零个、一个和多个数据;统计结果包含平均值、最大值或计数;代码不存在无限循环和除以零风险。
提交内容应包括源代码、三组测试输入与输出、一个曾经出现的错误及修复方法。最后请用自己的话解释本课最重要的概念;如果只能照着代码念,还需要再独立重写一次核心例子。