while 循环
while 循环是 C 语言中最基本的迭代结构,先判断条件,条件为真时执行循环体。它适合循环次数不确定、由运行时条件控制的场景。while 循环的三大要素——初始化、条件判断、更新——需要程序员显式管理,任何一个环节出错都可能导致无限循环或循环不执行。
基本语法
while (表达式)
语句
while (表达式) {
语句1;
语句2;
}
int i = 0; /* 初始化 */
while (i < 10) { /* 条件判断 */
printf("%d ", i); /* 循环体 */
i++; /* 更新 */
}
/* 输出:0 1 2 3 4 5 6 7 8 9 */
循环三大要素
一个完整的循环需要三个要素:
- 初始化:在进入循环前设置初始状态
- 条件:决定循环是否继续
- 更新:在每次迭代后修改状态
/* 读取直到文件结束 */
int c; /* 初始化 */
while ((c = getchar()) != EOF) { /* 条件 */
putchar(c); /* 循环体 */
/* 更新隐含在 getchar() 中 */
}
/* 计算阶乘 */
int n = 5;
int result = 1; /* 初始化 */
int i = 1;
while (i <= n) { /* 条件 */
result *= i; /* 循环体 */
i++; /* 更新 */
}
printf("%d! = %d\n", n, result); /* 5! = 120 */
循环可能一次都不执行
while 是前置条件判断,如果初始条件为假,循环体一次都不执行:
int i = 10;
while (i < 5) { /* 条件立即为假 */
printf("%d\n", i); /* 这行永远不会执行 */
i++;
}
这与 do-while 不同,后者至少执行一次。
无限循环
如果条件永远为真,循环不会结束:
/* 错误:忘记更新 */
int i = 0;
while (i < 10) {
printf("%d\n", i);
/* 忘记 i++ */
}
/* 故意的无限循环 */
while (1) {
/* 持续运行,直到内部 break */
if (should_stop())
break;
}
/* 更清晰的写法 */
for (;;) { /* 也是无限循环 */
/* ... */
}
空循环体
循环体为空时,用分号或空花括号表示:
/* 消耗输入直到换行 */
while (getchar() != '\n')
; /* 空语句 */
/* 或 */
while (getchar() != '\n') {
/* 空循环体 */
}
/* 查找字符串末尾 */
char *p = str;
while (*p != '\0')
p++; /* 循环体只有 p++ */
嵌套循环
while 可以嵌套使用:
int i = 0;
while (i < 3) {
int j = 0;
while (j < 3) {
printf("(%d,%d) ", i, j);
j++;
}
printf("\n");
i++;
}
/* 输出:
(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)
*/
与 for 循环的等价转换
while 和 for 可以互相转换:
/* while */
int i = 0;
while (i < 10) {
printf("%d\n", i);
i++;
}
/* 等价的 for */
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
一般规则:
- 已知循环次数 →
for - 未知循环次数,由条件控制 →
while - 至少执行一次 →
do-while
常见错误
忘记初始化:
int i; /* 未初始化 */
while (i < 10) { /* i 的值不确定! */
/* ... */
}
忘记更新:
int i = 0;
while (i < 10) {
printf("%d\n", i);
/* 忘记 i++ → 无限循环 */
}
条件错误:
int i = 0;
while (i = 10) { /* 赋值!i 变为 10,表达式值为 10(真) */
/* 无限循环 */
}
/* 正确 */
while (i == 10) { }
边界错误:
int i = 0;
while (i <= 10) { /* 执行 11 次(0 到 10) */
printf("%d\n", i);
i++;
}
/* 如果只需要 10 次 */
while (i < 10) { /* 执行 10 次(0 到 9) */
/* ... */
}
最佳实践
- 始终初始化循环变量
- 确保循环条件最终会变为假
- 在循环体内更新循环变量
- 使用
for处理已知次数的循环,while处理条件控制的循环 - 循环体始终使用花括号
- 注意边界条件(
<vs<=)