C while 与 do-while 循环
更新时间:2026-08-26。本文是
languages/c/主题入门层第 16 篇。for 适合"次数已知",while 适合"条件驱动"——什么时候停,由运行时的状态说了算。还有个小兄弟 do-while,它俩的区别就一句话:先判断还是先执行。
本文要回答的问题
- while 和 do-while 的差别到底是什么?
- 怎么用 while 处理"读输入直到合法"?
while(1)是不是坏味道?
一、while:先判断,再执行
int n = 0;
while (n < 3) {
printf("%d\n", n);
n++;
}
// 打印 0 1 2执行流程:判断条件 → 真则执行循环体 → 再判断……条件一开始为假,循环体一次都不执行。这是 while 和 do-while 的分水岭。
典型场景——等输入直到合法(条件驱动,次数未知):
int age;
printf("输入年龄(1-120):");
scanf("%d", &age);
while (age < 1 || age > 120) {
printf("年龄无效,请重新输入:");
scanf("%d", &age);
}
// 跳出循环时 age 一定合法这个模式叫"读入-校验-重试",是 while 最经典的用法——你无法预知用户要输错几次,只能"只要不合法就一直问"。
二、do-while:先执行,再判断
int n = 0;
do {
printf("%d\n", n);
n++;
} while (n < 3); // 注意这里有分号!
// 打印 0 1 2do-while 至少执行一次——不管条件真假,先进去再说。适合"无论如何都要做一次,再决定要不要继续"的场景:
int choice;
do {
printf("1. 开始 2. 退出\n");
scanf("%d", &choice);
// 处理选择...
} while (choice != 2); // 至少展示一次菜单别忘了结尾的分号——} while (...); 是 do-while 唯一必须以分号结尾的循环,漏写编译错误。
三、while vs do-while:什么时候用哪个
| 维度 | while | do-while |
|---|---|---|
| 判断时机 | 先判断 | 先执行 |
| 最少执行 | 0 次 | 1 次 |
| 适用 | 可能一次都不该执行 | 至少要做一次(菜单、重试) |
| 结尾 | 无分号 | 有分号 |
判断口诀:"进来再说"还是"先问问再进"。读文件读到结尾、遍历链表——这些用 while(可能本来就空);菜单循环、至少一次的重试——用 do-while。
四、无限循环:while(1)
while (1) {
// 事件循环、服务器主循环
if (收到退出信号) break;
}while(1) 不是坏味道——事件循环、服务器主循环天然就是"永远跑直到被中断"。关键是必须有退出路径(break、return、exit)。写 while(1) 而循环体里没有任何退出条件的,才是 bug。
顺带一提 while(1) 与 for(;;) 等价,现代编译器生成同样代码,选哪个纯属风格。
五、循环里 getchar 的经典模式
读一个字符直到文件结束(EOF):
int c;
while ((c = getchar()) != EOF) {
putchar(c); // 回显每个字符
}几个细节:
c必须是int而不是char(EOF 是 -1,char 可能放不下);- 赋值表达式外面必须加括号(
(c = getchar()) != EOF),否则被解析成c = (getchar() != EOF); - 这又是一个"赋值当比较"的变体,但这里是故意的。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| do-while 忘分号 | 编译错误 | } while (...); |
| 循环内忘了改条件变量 | 死循环 | 检查更新逻辑 |
| 用 while 写"至少一次" | 边界情况漏执行 | 改用 do-while |
(c = getchar()) != EOF 忘括号 | 行为错乱 | 括号包住赋值 |
| while(1) 无退出路径 | 死循环 | 保证有 break/return |
七、与本站主线衔接
- 循环与跳转的汇编形态(
jmp回跳),见与汇编、性能剖析衔接; getchar与输入缓冲区的机制,见scanf 与输入缓冲区陷阱;break与continue的详细规则,见下一篇 break 与 continue。
一句话总结
while 先判断后执行(可能 0 次)、do-while 先执行后判断(至少 1 次,记得结尾分号);"等输入直到合法"用 while、"菜单至少展示一次"用 do-while,while(1) 配 break 是合法的事件循环。