循环 — for/while 重复执行
C语言学习教程
循环 — for/while 重复执行
🌟 生活中的”循环”
生活中到处都是循环:
- 每天早上 重复 刷牙、洗脸、吃早饭。
- 操场跑圈:第 1 圈、第 2 圈…第 5 圈,跑完停下来。
- 超市结账:只要购物车里还有东西,就重复扫码,直到空了为止。
- 手机解锁:反复输入密码,直到正确为止(或者次数超限)。
程序也是一样。当你需要做重复的事情时,不可能把同一段代码复制粘贴 100 遍。循环就是用来解决”重复执行”的问题——写一次,执行多次。
一句话总结:循环让一段代码能够反复运行。C 语言提供了三种循环方式:
for、while、do-while,外加break和continue两个控制开关。
📖 概念详解 — 三种循环,各司其职
循环的四要素
任何循环都包含四个要素,缺一不可:
| 要素 | 说明 | 示例 |
|---|---|---|
| ① 初始化 | 循环开始前的准备工作 | int i = 0; |
| ② 条件 | 每次循环前检查,决定继续还是退出 | i < 10; |
| ③ 循环体 | 每次循环要执行的代码 | printf(...) |
| ④ 更新 | 每次循环后改变条件变量 | i++; |
缺少任何一个要素,循环要么不执行,要么停不下来(死循环)。
for 循环流程
┌──────────────┐
│ ① 初始化 │ ← 只执行一次
│ int i = 0; │
└──────┬───────┘
│
┌────▼────┐
│ ② 条件? │ ← 每次循环前检查
│ i < 5? │
└────┬─────┘
真 ╱ ╲ 假
▼ ▼
┌──────────┐ ┌──────────┐
│ ③ 循环体 │ │ 退出循环 │
│ printf │ └──────────┘
└────┬─────┘
│
▼
┌──────────┐
│ ④ 更新 │ ← 每次循环后执行
│ i++ │
└────┬─────┘
│
└────→ 回到 ②
while 循环流程
┌──────────────┐
│ 初始化在循环 │
│ 之前完成 │
└──────┬───────┘
│
┌────▼────┐
┌───→│ 条件? │ ← 先判断
│ │ i < 5? │
│ └────┬─────┘
│ 真 ╱ ╲ 假
│ ▼ ▼
│ ┌──────┐ ┌──────┐
│ │循环体 │ │ 退出 │
│ └──┬───┘ └──────┘
│ │
│ ▼
│ ┌──────┐
│ │ 更新 │ ← 循环体内手动写
│ │ i++ │
│ └──┬───┘
│ │
└─────┘
do-while 循环流程(关键区别)
┌──────────────┐
│ 初始化在循环 │
│ 之前完成 │
└──────┬───────┘
│
┌────▼────┐
┌───→│ 循环体 │ ← 先执行!
│ │ 更新 │ 不管条件先跑一次
│ └──┬─────┘
│ │
│ ┌────▼────┐
│ │ 条件? │ ← 执行完再判断
│ │ i < 5? │
│ └────┬─────┘
│ 真 ╱ ╲ 假
│ ▼ ▼
└─────┘ ┌──────┐
│ 退出 │
└──────┘
核心对比:while 是”先检查再进门”,do-while 是”先进门再检查”——所以 do-while 至少执行一次。
💻 代码示例 — 从计数器到实用场景
示例 1:for 循环 — 打印 1 到 10
#include <stdio.h>
int main() {
printf("正序打印 1 到 10:\n");
for (int i = 1; i <= 10; i++) {
// i=1 → 打印 → i=2 → 打印 → ... → i=10 → 打印 → i=11 → 退出
printf("第 %d 次循环,i = %d\n", i, i);
}
printf("\n倒序打印 10 到 1:\n");
for (int i = 10; i >= 1; i--) {
printf("%d ", i);
}
printf("\n发射!🚀\n");
return 0;
}
拆解 for 的三个部分:
int i = 1— 初始化(只做一次)i <= 10— 条件(每次循环前检查,不满足就退出)i++— 更新(每次循环后执行)
循环走了 10 次,i 的值依次是 1, 2, 3, …, 10。当 i 变成 11 时,i <= 10 为假,退出。
示例 2:for 循环 — 灵活使用(步长、多变量)
#include <stdio.h>
int main() {
// 步长为 2:打印 0 到 20 的偶数
printf("0 到 20 的偶数:\n");
for (int i = 0; i <= 20; i += 2) {
printf("%d ", i);
}
printf("\n\n");
// 步长为 5:打印 0 到 100 的 5 的倍数
printf("0 到 100 中 5 的倍数:\n");
for (int i = 0; i <= 100; i += 5) {
printf("%d ", i);
}
printf("\n\n");
// 双变量:一头一尾向中间靠拢
printf("双变量向中间靠拢:\n");
for (int left = 1, right = 10; left <= right; left++, right--) {
printf("left = %d, right = %d\n", left, right);
}
// 循环变量提前声明(C99 前必须这样写)
printf("\n老式写法(变量在 for 外声明):\n");
int i;
for (i = 0; i < 3; i++) {
printf("%d ", i);
}
printf("\n循环结束后 i = %d(在外面还能用!)\n", i);
return 0;
}
注意:在 for(int i = 0; ...) 中声明的 i,只在循环内部有效。如果需要在循环后继续使用 i,要在 for 之前声明。
示例 3:while — 不知道循环多少次时使用
#include <stdio.h>
int main() {
int num;
int sum = 0;
int count = 0;
printf("请输入若干个整数(输入 0 结束):\n");
// 不知道用户会输多少个数字 → 用 while
printf("第 1 个数: ");
scanf("%d", &num);
while (num != 0) { // num 不为 0 就一直循环
sum += num; // 累加
count++; // 计数
printf("第 %d 个数: ", count + 1);
scanf("%d", &num);
}
if (count > 0) {
printf("\n共输入 %d 个有效数字\n", count);
printf("总和 = %d\n", sum);
printf("平均值 = %.2f\n", (double)sum / count);
} else {
printf("没有输入任何有效数字。\n");
}
return 0;
}
while 的典型场景:
- 读取用户输入直到某个终止标志
- 从文件中读取数据直到文件结束
- 游戏循环:只要玩家没有退出,就继续
示例 4:do-while — 至少执行一次
#include <stdio.h>
int main() {
int password = 1234;
int input;
int attempts = 0;
const int MAX_ATTEMPTS = 3;
// 至少让用户输入一次密码
do {
printf("请输入密码: ");
scanf("%d", &input);
attempts++;
if (input == password) {
printf("✅ 密码正确!欢迎回来。\n");
break; // 密码对了就退出
} else {
printf("❌ 密码错误");
if (attempts < MAX_ATTEMPTS) {
printf(",还剩 %d 次机会。\n", MAX_ATTEMPTS - attempts);
} else {
printf(",次数已用完!\n");
}
}
} while (input != password && attempts < MAX_ATTEMPTS);
if (attempts >= MAX_ATTEMPTS && input != password) {
printf("账户已锁定,请稍后重试。\n");
}
return 0;
}
do-while 的典型场景:
- 密码验证:至少输入一次
- 菜单交互:先显示菜单,再根据用户选择决定是否继续
- 游戏:先玩一局,再问”还要继续吗?“
示例 5:break 与 continue — 循环的控制开关
#include <stdio.h>
int main() {
// ========== break:立即退出循环 ==========
printf("=== break 演示 ===\n");
printf("遇到第一个能被 7 整除的数就停止:\n");
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
printf("找到了:%d 能被 7 整除!\n", i);
break; // 立刻跳出循环,后面的 i 都不检查
}
}
// 输出:找到了:7 能被 7 整除!
printf("\n=== 在嵌套循环中用 break ===\n");
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 5; j++) {
if (j == 3) {
printf(" 内层 j=%d 触发了 break\n", j);
break; // 只跳出内层循环!
}
printf(" i=%d, j=%d\n", i, j);
}
printf("外层 i=%d 继续...\n", i);
}
// 注意:break 只跳出最近的一层循环,外层不受影响
// ========== continue:跳过本次循环,继续下一次 ==========
printf("\n=== continue 演示 ===\n");
printf("打印 1-20 中的奇数(跳过偶数):\n");
for (int i = 1; i <= 20; i++) {
if (i % 2 == 0) {
continue; // 偶数就跳过,不执行后面的 printf
}
printf("%d ", i);
}
printf("\n");
// 统计非跳过的次数
printf("\n统计 1-100 中不能被 3 整除的数的个数:\n");
int count = 0;
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0) {
continue; // 能被 3 整除就跳过
}
count++;
}
printf("共有 %d 个(预期 100 - 33 = 67)\n", count);
return 0;
}
记忆口诀:
break= 摔门而出(循环彻底结束)continue= 跳过本页(本次结束,下次继续)
示例 6:嵌套循环 — 经典九九乘法表
#include <stdio.h>
int main() {
printf("=====================\n");
printf(" 九九乘法表\n");
printf("=====================\n");
// 外层循环:被乘数 i(行)
for (int i = 1; i <= 9; i++) {
// 内层循环:乘数 j(列)
for (int j = 1; j <= i; j++) {
// %-4d 表示左对齐,占 4 个字符宽度
printf("%d×%d=%-4d", j, i, i * j);
}
printf("\n"); // 每行结束换行
}
printf("\n详细解读:\n");
printf("外层 i=1 时,内层 j 从 1 到 1 → 打印 1×1=1\n");
printf("外层 i=2 时,内层 j 从 1 到 2 → 打印 1×2=2 2×2=4\n");
printf("外层 i=3 时,内层 j 从 1 到 3 → 打印 3 个式子\n");
printf("...\n");
printf("外层每执行 1 次,内层执行一整轮\n\n");
// 用表格展示嵌套循环的执行顺序
printf("执行顺序追踪(部分):\n");
printf("i=1, j=1 | i=2, j=1 | i=2, j=2 | i=3, j=1 | i=3, j=2 | i=3, j=3 | ...\n");
return 0;
}
嵌套循环执行规律:外层一次,内层一轮。总执行次数 = 外层次数 × 内层次数。
⚠️ 常见错误 — 循环写不对,问题多在这些地方
错误 1:while 后面多了分号(死循环!)
| 错误写法 | 正确写法 |
|---|---|
while (i < 5); | while (i < 5) |
// ❌ 错误演示(这段代码会卡死!)
int i = 0;
while (i < 5); { // 分号!while 在一个空语句上死循环
printf("%d\n", i);
i++;
}
// i 永远是 0,条件永远为真,程序卡死!
// ✅ 正确写法
int i = 0;
while (i < 5) { // 没有分号
printf("%d\n", i);
i++;
}
// 输出:0 1 2 3 4
和 if 一样,一个逗号就能毁掉整个循环。
错误 2:忘记更新循环变量(死循环!)
// ❌ 错误演示
int i = 0;
while (i < 5) {
printf("%d ", i);
// 忘记 i++!
}
// i 永远为 0,死循环!
// ✅ 正确写法
int i = 0;
while (i < 5) {
printf("%d ", i);
i++; // 必须更新!
}
错误 3:循环变量的作用域问题
#include <stdio.h>
int main() {
// ❌ 在 for 内部声明的变量,循环外不可用
for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
// printf("%d", i); // 编译错误!i 已不在作用域内
// ✅ 如果需要在循环外使用 i
int i;
for (i = 0; i < 5; i++) {
printf("%d ", i);
}
printf("\n循环结束后 i = %d\n", i); // OK,输出 5
return 0;
}
错误 4:嵌套循环用同一个变量名
// ❌ 错误演示
for (int i = 1; i <= 3; i++) {
for (int i = 1; i <= 3; i++) { // 内外层都用 i!
printf("*"); // 内层的 i 会干扰外层
}
printf("\n");
}
// 行为不可预测!
// ✅ 正确写法:内外层用不同名字
for (int i = 1; i <= 3; i++) { // 外层 i
for (int j = 1; j <= 3; j++) { // 内层 j
printf("*");
}
printf("\n");
}
错误 5:边界条件差 1(off-by-one 错误)
// ❌ 想打印 10 次,结果打印了 11 次
for (int i = 0; i <= 10; i++) { // 0,1,2,...,10 → 11 次!
printf("%d ", i);
}
// 想打印 10 次,结果只打印了 9 次
for (int i = 1; i < 10; i++) { // 1,2,...,9 → 9 次!
printf("%d ", i);
}
// ✅ 打印 10 次的标准写法(任选一种)
for (int i = 0; i < 10; i++) // 0,1,...,9 → 10 次 ✓
for (int i = 1; i <= 10; i++) // 1,2,...,10 → 10 次 ✓
规则:
i < N→ 循环 N 次,i 从 0 到 N-1i <= N→ 循环 N 次,i 从 1 到 N(i 初值为 1)- 养成习惯:写循环前先在脑子里默数前 3 次的值。
错误 6:do-while 结尾忘记分号
// ❌ 编译错误
int i = 0;
do {
printf("%d", i);
i++;
} while (i < 5) // 缺少分号!
// ✅ 正确写法
int i = 0;
do {
printf("%d", i);
i++;
} while (i < 5); // do-while 结尾必须有分号
记忆技巧:
while(...)语句以分号结尾的,只有 do-while。普通 while 后面没有分号。
💡 练习建议
- 单步调试:用一个简单的 for 循环,在 IDE 中设置断点,单步执行观察 i 的变化。亲眼看着变量的值如何一步步变化,比任何文字解释都直观。
- 在纸上跑流程:遇到复杂的嵌套循环,用纸笔一行行追踪变量的值。这对建立循环的直觉非常有帮助。
- 改写练习:把一个 for 循环改成 while,再改成 do-while,体会三者的异同。并非所有循环都能互相改写(do-while 的”至少一次”语义 for/while 模拟不了)。
- 先写内层再写外层:写嵌套循环时,先把内层逻辑独立写对,再套上外层。
- 故意写死循环:写一个
while(1)或for(;;),然后在里面用break退出。理解无限循环 + break 的设计模式(这在实际项目中很常见,比如服务器主循环)。
📝 要点速查
| 要点 | 说明 |
|---|---|
for(初始化; 条件; 更新) | 三要素内聚,适合已知次数的循环 |
while(条件) | 先判断再执行,适合未知次数 |
do {...} while(条件); | 先执行再判断,至少一次 |
break | 立即退出当前循环(只退一层) |
continue | 跳过本次循环剩余代码,继续下一次 |
| 嵌套循环 | 外层一次 → 内层一轮 |
for(;;) | 无限循环(等价于 while(1)) |
| 循环四要素 | 初始化、条件、循环体、更新,缺一不可 |
三种循环选择指南
需要循环 → 知道执行多少次?
├── 是 → 用 for
└── 否 → 至少执行一次?
├── 是 → 用 do-while
└── 否 → 用 while
🔗 相关主题
- 条件判断 — if/else 与 switch — 循环内常用 if 判断何时 break/continue
- 数组 — 数据的有序集合 — 循环最常见的用途就是遍历数组
- 函数 — 代码复用的基本单元 — 把循环逻辑封装在函数中
- 练习 — 控制流综合题 — 条件判断和循环的综合练习