Menu

C++ while 循环:语法、do-while 与常见陷阱

详解 C++ while 循环:先判断条件的 while、至少执行一次的 do-while、循环直到遇到哨兵值、break 和 continue,以及如何避免死循环。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

没有计数器的时候

for 循环是围绕一个事先设好的计数器构建的。但很多循环并没有明确的次数:不断读取数字直到输入结束,不断要求输入密码直到正确,不断把一个值减半直到它变成 1。对于这些情况,while 循环是最自然的选择:只要条件保持为 true,它就一直重复。

while 循环在每次执行之前都会检查条件,包括第一次。如果条件一开始就是 false,循环体根本不会执行。

先检查条件 count > 0;如果为 true 就执行循环体,然后回到开头再次检查。count-- 这一行最终会让条件变为 false,去掉它,循环就会永远运行下去。

while 循环的结构

把它和你已经熟悉的三段式 for 循环比较一下。while 循环把这三件事拆开了:初始化在循环之前完成,条件写在括号里,更新则放在循环体内部。

int i = 0;          // initialization - before the loop
while (i < 5) {     // condition - checked each pass
    cout << i << "\n";
    i++;            // update - you must remember this yourself
}

最后一点正是要注意的地方。在 for 循环中,更新部分就紧挨着条件,很难忘记。而在 while 循环中,它只是循环体里的又一条语句,最常见的 bug 就是漏写了它,导致程序卡死。

还有一个专坑初学者的 C++ 陷阱:条件后面多出的一个分号,会让循环体变成一条空语句。

int i = 0;
while (i < 5);   // <-- this semicolon is the entire loop body
{
    cout << i << "\n";
    i++;
}

这会什么也不做地永远循环下去,因为 ; 就是循环体,而 i 永远不会改变。花括号里的代码块随后只会执行一次。编译器不会阻止你:这是完全合法的代码,只是不是你想要的。

do-while:至少执行一次循环体

有时你需要先执行一次循环体,才能决定是否要重复。do-while 循环在底部检查条件,所以循环体总是至少执行一次:

你必须至少提示并读取一次,才能知道输入是否有效,而这正是 do-while 提供的。注意 while (...) 后面的分号:在 C++ 中,do-while 必须写这个分号,忘了它是常见的编译错误。

当条件一开始就是 false 时,它和普通 while 的区别就一目了然了:

只有 do-while body 被打印出来。while 循环完全跳过了它的循环体,因为在第一次检查之前 x < 5 就已经是 false。

循环直到 cin 失败

while 的一个经典用法是一直读取,直到输入停止:没有计数器,只是一直读下去,直到输入流告诉你该结束了。在 C++ 中,cin >> value 的求值结果就是输入流本身,读取成功时它为真,一旦遇到输入结束或类型不匹配就为假。这让它成为一个简洁的循环条件:

这个条件身兼两职:一步之内既读取又检测。再对比一下哨兵值的写法,比如遇到 0 就停止。这时你必须在循环之前读取一次,并在每次循环的末尾再读取一次,让条件检测的始终是新输入:

如果忘了循环体内的第二次读取,value 就永远不会改变,你就得到了一个死循环。while (cin >> value) 这种写法把读取并入了条件,从而避开了这个问题。

while 循环中的 break 和 continue

break 和 continue 在这里的作用和在 for 循环中一样。break 立即离开循环;continue 直接跳回条件检查,跳过本次循环剩下的部分:

这会打印 1 3 5 7 9。while (true) 有意设计成自己永远不会停下来,break 是唯一的出口。在 while 循环中使用 continue 要小心:因为更新是循环体的一部分,在推进计数器之前就用 continue 跳回开头,是让循环悄悄卡死的一种方式。上面的例子中 n++ 先执行,所以是安全的。

当心死循环

条件最终必须变为 false,而这完全取决于循环体内有没有东西在改变。两个常见的元凶是:忘了更新,以及更新的方式恰好跳过了退出值:

int i = 0;
while (i < 5) {
    cout << i << "\n";   // i never changes -> runs forever
}
int i = 0;
while (i != 10) {
    i += 3;   // 0, 3, 6, 9, 12... steps right past 10 -> runs forever
}

第一个卡住是因为 i 从未更新。第二个卡住是因为计数器跨过了条件要找的那个确切的值:当步长不一定能正好落在目标值上时,优先用 < 或 <= 而不是 !=。while (true) 本身没问题,前提是它有一个必定会执行到的 break;意外写出来的那种就只是 bug。还要记住前面讲过的空循环体 while (...); 陷阱:一个放错位置的分号,会产生一个乍看之下完全正确的死循环。

下一步:基于范围的 for 循环

当你需要一直循环到条件改变、又没有明确的次数时,while 循环是合适的工具。但如果你只是想访问容器(vector、数组、string)中的每一个元素,不需要管理下标,也没有条件要维护,现代 C++ 有更简洁的写法:基于范围的 for 循环(for (auto x : container))。这就是下一页的内容。

常见问题

C++ 中 while 和 do-while 有什么区别?

while 循环在第一次执行之前就检查条件,所以循环体可能一次都不执行。do-while 循环先执行一次循环体,再在底部检查条件,所以它至少会执行一次。当必须先做某件事才能决定是否重复时(比如先提示输入,再验证输入),就用 do-while。注意 do-while 在结尾的 while (...) 之后需要一个分号。

C++ 中什么时候该用 while 循环而不是 for 循环?

当你没有一个明确的计数器,只想一直重复到某个条件改变时,就用 while 循环:读取输入直到 cin 失败、轮询直到某个值就绪、处理队列直到它为空。当你知道循环次数,或者有一个明显可以计数的下标时,就用 for 循环。

C++ 中如何停止一个死循环的 while 循环?

确保循环体内有某个操作最终会让条件变为 false(让计数器递减、移动指针、设置一个标志)。对于有意写的 while (true) 循环,要在里面放一个由 if 控制的 break。如果循环卡住了,通常的原因是忘了更新条件所依赖的那个变量。

Coddy 编程语言插图

和 Coddy 一起学编程

开始