循环运行过程中,有时需要提前结束循环,或者跳过某一次不做处理。break 和 continue 就是控制循环流程的两个关键字。
5.4
循环运行过程中,有时需要提前结束循环,或者跳过某一次不做处理。break 和 continue 就是控制循环流程的两个关键字。
break 后,立即终止当前循环,继续执行循环后面的代码。也可用于跳出 switch。continue 后,跳过本次循环体中剩余的代码,直接进入下一次迭代,循环不会终止。break 关键字用于跳出当前所在的循环(或 switch),继续执行循环后面的代码。常用于"找到了就没必要继续找下去"的场景:
| 1 | for (int i = 1; i <= 100; i++) |
| 2 | { |
| 3 | if (i % 7 == 0) |
| 4 | { |
| 5 | cout << "第一个被7整除的数是:" << i << endl; |
| 6 | break; // 找到了就立刻跳出,不再继续 |
| 7 | } |
| 8 | } |
| 9 | // 输出:第一个被7整除的数是:7 |
continue 关键字用于跳过当前循环的剩余部分,直接进入下一次迭代。它不会终止循环,只是跳过本次迭代中剩余的代码:
| 1 | for (int i = 1; i <= 10; i++) |
| 2 | { |
| 3 | if (i % 2 == 0) |
| 4 | { |
| 5 | continue; // 偶数:跳过本次,不执行 cout |
| 6 | } |
| 7 | cout << i << " "; // 只有奇数才到这里 |
| 8 | } |
| 9 | // 输出:1 3 5 7 9 |
break 是"我不想玩了,退出循环";continue 是"这次跳过,下一轮继续玩"。break 和 continue 都只作用于它们所在的最内层循环,不会影响外层循环:
| 1 | for (int i = 1; i <= 3; i++) // 外层 |
| 2 | { |
| 3 | for (int j = 1; j <= 3; j++) // 内层 |
| 4 | { |
| 5 | if (j == 2) break; // 只跳出内层 for(j...) |
| 6 | cout << i << "," << j << " "; |
| 7 | } |
| 8 | } |
| 9 | // 输出:1,1 2,1 3,1 —— 外层照常跑满 3 轮,每轮内层只打印 j=1 就 break |
如果确实需要"一次性跳出所有层",常见做法是用一个标志变量记录"是否需要终止",外层循环每轮开始时检查这个标志:
| 1 | bool found = false; // 标志变量:是否已经找到目标 |
| 2 | for (int i = 1; i <= 3 && !found; i++) // 外层:加上 !found 条件 |
| 3 | { |
| 4 | for (int j = 1; j <= 3; j++) |
| 5 | { |
| 6 | if (i == 2 && j == 2) |
| 7 | { |
| 8 | found = true; // 标记找到,外层下一轮会因为 !found 而停止 |
| 9 | break; // 先跳出内层 |
| 10 | } |
| 11 | } |
| 12 | } |
这段代码的关键在第 9 行和第 2 行的配合:break 先跳出内层循环,但外层循环本身并不知道"已经找到了"——真正让外层停下来的,是外层 for 条件里的 && !found。found 变成 true 后,!found 就变成 false,外层循环在下一轮开始判断条件时就会自动终止,不需要再跳一次。这是 C++ 里跳出多层循环的常用模式——原生语法没有"一次性跳出所有层"的关键字,只能靠标志变量 + 条件判断来实现。
把本节内容汇总成几条最容易踩坑的规则:
break 只能跳出最内层的循环,外层会继续正常运行。需要一次性终止所有层时,要用标志变量或把逻辑提取成函数用 return 退出。while 循环里非常隐蔽的坑——如果更新语句(比如 i++)写在 continue判断之后,一旦触发 continue,更新语句会被跳过,条件永远不变,循环永远不会结束。for 循环不会有这个问题,因为它的更新语句在结构上独立于循环体,即使触发 continue 也一定会执行。switch 语句嵌套在循环内部,switch 里的 break 只会跳出 switch 本身,并不会影响外层的循环,这一点容易和"break 跳出循环"的直觉混淆。先看陷阱 2:continue 跳过更新语句导致死循环,具体会踩坑到什么程度?下面这段代码就是一个真实的反面例子——
| 1 | int i = 0; |
| 2 | while (i < 10) |
| 3 | { |
| 4 | if (i % 2 == 0) |
| 5 | { |
| 6 | continue; // ⚠️ 偶数时直接跳过下面的 i++ |
| 7 | } |
| 8 | cout << i; |
| 9 | i++; // ⚠️ i=0 时 continue 会跳过这一行,i 永远是 0,死循环! |
| 10 | } |
逐行走一遍:i 从 0 开始,i % 2 == 0 成立,直接 continue——回到第 2 行重新判断条件,第 9 行的 i++ 完全没机会执行。于是 i 永远停在 0,条件 i < 10 永远为真,程序卡死在这个循环里出不来。
while/do-while 循环中使用 continue 时,一定要确保更新语句在 continue 触发之前就已经执行,或者把更新语句挪到 continue 判断的前面。这也是为什么"循环次数已知"的场景更推荐用 for——更新语句在结构上独立出来,天然不会被 continue 波及。再看陷阱 3:switch 嵌套在循环里时,switch 自己的 break 到底管到哪一层?
| 1 | for (int i = 0; i < 5; i++) |
| 2 | { |
| 3 | switch (i) |
| 4 | { |
| 5 | case 2: |
| 6 | break; // 只跳出 switch,不影响外层 for |
| 7 | } |
| 8 | cout << i; // i=2 这一轮同样会执行到这里,输出 0 1 2 3 4 |
| 9 | } |
i == 2 那一轮,case 2 匹配上,执行到第 6 行的 break——但这个 break 只是让程序跳出 switch 这对花括号,回到 for 循环体里 switch 之后的位置,继续往下执行第 8 行的 cout,然后正常进入下一轮 i++。整个 for 循环完全没有被提前终止,最终会正常输出 0 1 2 3 4。