第二阶段第5周

条件判断与循环控制

这一周你会让程序真正“动起来”:会判断、会分支、会重复执行。关键是每条逻辑路径都清楚、可验证。

学完这周,你能把现实规则翻译成 `if/else`、`switch`、`for`、`while`,并能自己排查死循环和分支错误。

C++ 第二阶段第5周课程封面

5.1 学习重点

先练分支,再练循环,最后做组合练习。拆开训练更容易发现问题,也更容易稳定进步。

本周达成:你可以独立写出包含判断和循环的控制台程序,并验证每条路径是否正确。

5.2 条件判断

`if/else` 适合范围判断,`switch` 适合固定选项。写条件时注意边界,`>= 60` 和 `> 60` 会得到不同结论。

int score = 78;
if (score >= 90) {
    cout << "A\n";
} else if (score >= 75) {
    cout << "B\n";
} else if (score >= 60) {
    cout << "C\n";
} else {
    cout << "D\n";
}

5.3 循环控制

`for` 常用于次数明确的任务,`while` 常用于条件驱动任务。循环代码一定要先确认退出条件,避免卡死。

int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
cout << "1 到 100 的和: " << sum << "\n";

5.4 分支 + 循环组合

组合时建议“先循环,再在循环体内判断”。例如批量处理成绩时,先遍历每个成绩,再判断是否合法。

vector<int> scores = {95, 82, -1, 76, 120, 60};
int validCount = 0;
for (int s : scores) {
    if (s < 0 || s > 100) {
        cout << "非法分数: " << s << "\n";
        continue;
    }
    validCount++;
}
cout << "合法分数数量: " << validCount << "\n";

5.5 深度讲解:条件分支如何写得稳定

判断语句最常见的问题不是“不会写”,而是“写出来以后隐藏 bug 很多”。比如你在成绩判断里先写了 `if (score >= 60)`,后面再写 `else if (score >= 90)`,那 `>= 90` 永远不会触发,因为前面的条件已经把它拦截了。这个错误在初学阶段非常常见,原因是同学只关注单条条件,不关注条件之间的顺序关系。建议你把分支当成“从上到下的筛选器”,先筛最严格条件,再筛宽松条件。排序正确后,分支逻辑就会稳定很多。

第二个高频问题是边界重叠或空洞。比如你写 `if (x > 0 && x < 10)`,`else if (x > 10 && x < 20)`,那 `x == 10` 会落到哪里?如果你没有显式覆盖,它就会掉进意料之外的分支。写条件时建议先在纸上列出关键边界值:最小值、最大值、临界值。然后逐个代入每条条件,确认每个值都能落到正确分支。这个动作非常简单,但能一次性发现大量逻辑漏洞。

第三个问题是条件可读性。很多同学喜欢把复杂逻辑一口气写进 `if`,结果自己两天后都看不懂。比如 `if ((a>0&&b<5)||(!flag&&c==3)||...)` 这种写法可运行,但不利于维护。更推荐做法是把条件拆成有意义的布尔变量:`bool isValidAge`、`bool hasPermission`、`bool isTimeAllowed`,最后再组合判断。可读性不是“锦上添花”,它直接决定你调试速度和协作效率。

5.6 深度讲解:循环边界、终止条件与性能意识

循环控制的核心是三件事:从哪里开始、执行多少次、何时结束。任何一个点模糊,程序就容易出错。比如 `for (int i = 0; i <= n; i++)` 与 `for (int i = 0; i < n; i++)` 的差别是是否多执行一次。这个“+1/-1”错误在数组访问中尤其危险,因为它可能导致越界访问。你可以给自己一个固定动作:写完循环后先口头读一遍“i 从几到几,总共跑几次”,确认和题目一致再运行。

在 `while` 循环里,最容易发生的是忘记更新状态。比如读取用户输入后没有更新变量,程序就会一直停在旧条件里。解决办法是把“状态更新语句”放在你一眼就能看到的位置,不要埋在复杂分支深处。还有一个实用技巧:在调试阶段打印循环轮次和关键变量值,例如 `cout << "round=" << round << ", hp=" << hp << "\n";`。这能让你快速看见程序是否在向终止条件靠近。

另外,你可以在本周开始建立最基础的性能意识:重复计算能否提前缓存?循环里是否有不必要的 IO 输出?例如某些常量可以放到循环外,避免每次重复计算。虽然当前项目规模还小,但这个思维会在后续大型项目里帮你节省很多时间。请记住:先保证正确,再考虑效率;但在保证正确的前提下,写出结构清楚的循环,本身就是效率优化的一部分。

int n = 0;
cout << "请输入要处理的数据个数: ";
cin >> n;

if (n <= 0) {
    cout << "个数必须大于 0。\n";
    return 0;
}

int valid = 0;
for (int i = 0; i < n; i++) {
    int score = 0;
    cin >> score;
    if (score < 0 || score > 100) continue;
    valid++;
}
cout << "合法数据数量: " << valid << "\n";

5.7 学习策略:用“路径测试”验证控制流

这一周特别推荐你使用“路径测试”方法。路径测试的思路是:不是只看最终结果,而是确认每一条分支路径都至少走过一次。比如菜单计算器有 1 到 5 五个选项,你就至少准备五组输入,让每个选项都被触发。若某个分支从未被执行,你就无法证明它正确。很多线上 bug 都来自“逻辑写了但从没测过”。

你还可以做一份简化测试表:输入、预计进入分支、预期输出、实际输出、是否一致。这个表格看起来像“额外工作”,其实是你进步最快的工具。因为它把“我感觉程序差不多对了”变成“我有证据说明程序正确”。长期坚持后,你会形成非常强的工程思维:先定义行为,再验证行为,最后才发布结果。

最后提醒一点:不要惧怕重构。发现分支太乱、循环太深时,勇敢拆函数、拆变量、拆步骤。代码不是一次写完不动的作文,而是可以持续迭代的系统。你在第二阶段养成的每个好习惯,都会在后续项目里放大收益。

5.8 课堂问答与进阶练习

问:`if` 和 `switch` 怎么选? 如果是范围判断(例如分数区间、血量阈值),优先 `if/else`;如果是固定枚举(例如菜单选项 1 到 5),优先 `switch`。选择标准不是“哪种更酷”,而是“哪种更容易读懂和维护”。写团队代码时,可读性永远优先。

问:为什么我总是出现死循环? 因为循环变量没有按预期变化,或者退出条件永远不会成立。最实用的办法是打印“轮次 + 关键变量”,例如 `round`、`choice`、`hp`,观察它们是否朝终止方向变化。只要变量不变,循环就不可能结束。这个定位思路比盲改代码高效得多。

问:怎么判断循环边界写对了? 先用一句话说清“应该执行几次”,再反推边界表达式。比如“处理 10 个元素”,通常写 `i = 0` 到 `i < 10`。然后用最小样例验证,例如只给 1 个元素,看循环是否恰好跑 1 次。这个方法对 `for` 和数组遍历尤其有效。

进阶练习建议:实现“关卡结算器”。输入玩家每关得分,程序循环读取直到输入 `-1` 结束,然后输出总分、平均分、最高分和最低分,并根据平均分给出评级。要求: 第一,非法分数(小于 0 且不等于 -1,或大于 100)必须提示并忽略; 第二,至少用一个 `continue` 和一个 `break`; 第三,给出测试清单,覆盖空输入、全非法输入、正常混合输入三种场景。

建议你把这次作业当成“控制流能力验收”:不是看程序有多长,而是看每条路径是否可解释、可复现、可验证。只要你能清楚说明“程序为什么在这个输入下走这条路”,就说明你真正掌握了条件与循环。

5.9 本周练习与自测清单

本周练习

  1. 完成菜单计算器(循环显示菜单,支持四则运算与退出)。
  2. 补充“猜数字”循环版并统计尝试次数。
  3. 提交至少 6 组测试结果。

自测清单

复盘模板建议:第一,写出本周你最容易漏测的 3 条路径;第二,为每条路径补 1 组最小输入;第三,记录“错误现象 -> 根因 -> 修复动作 -> 防复发规则”。坚持这样做两到三周,你会明显感觉控制流 bug 数量下降。很多同学卡在“会写但不稳”,本质就是缺少系统复盘。把复盘变成固定动作,你的代码质量会上一个台阶。

额外挑战:把菜单计算器扩展成“连续任务模式”,允许用户一轮内执行多次运算并输出历史记录。这个挑战会让你练到循环嵌套、状态管理和退出逻辑,能很好检验你是否真正掌握控制流。

错误案例提醒:如果你发现某个分支“总是进不去”,先检查它前面的分支是否已把条件覆盖;如果循环“跑不完”,优先检查变量是否在每轮正确更新。

最后提醒:控制流正确性永远比代码炫技更重要。

返回 C++ 第二阶段