第五章第二节:循环结构(while/do-while/for)
第二节:循环结构 ——while、do-while 和 for
上一节我们学习了分支结构 —— 程序会 "思考" 了,能根据条件做选择。
但如果我想让程序重复做一件事呢?比如:
- 打印 100 遍 "我爱编程"
- 计算 1 加到 100 的和
- 输出九九乘法表
如果没有循环,你就得写 100 遍、甚至更多遍相同的代码 —— 这也太蠢了。
这时候就需要循环结构了。循环就是让程序重复执行一段代码,直到满足某个条件才停止。
C 语言提供了三种循环语句:
while循环:先判断,后执行,适合不知道循环次数的场景do-while循环:先执行,后判断,至少执行一次for循环:最灵活、最常用,适合知道循环次数的场景
本节我们就把这三种循环一网打尽,再加上break、continue和循环嵌套,让你彻底掌握循环!
准备好了吗?Let's go!
一、什么是循环结构?
循环结构就是根据条件,重复执行一段代码(叫循环体)。
就像跑步:
- 条件:还没跑够 3 圈
- 循环体:继续跑
- 每跑一圈检查一次,直到跑够了就停下来
┌───────────────┐ ↓ │ 判断条件 │ │ │ 为真 → 执行循环体 ─┘ 为假 → 结束循环循环有三个关键要素:
- 初始值:循环从哪里开始
- 条件判断:什么时候结束
- 更新:每次循环后改变什么,让条件最终能变成假
少了任何一个,都可能出问题(比如死循环)。
二、while 循环
while是最简单的循环,也是最基础的。
2.1 基本语法
while (条件) { // 循环体:条件为真时,重复执行这里的代码 }执行流程:
- 先判断括号里的条件
- 如果条件为真,就执行循环体
- 执行完循环体,回到第 1 步,再判断条件
- 如果条件为假,就结束循环,继续往下执行
特点:先判断,后执行。如果一开始条件就是假的,循环体一次都不执行。
2.2 第一个例子:打印 1 到 5
#include <stdio.h> int main() { int i = 1; // ① 初始值:从1开始 while (i <= 5) // ② 条件:小于等于5就继续 { printf("%d ", i); i++; // ③ 更新:每次加1,否则永远是1,死循环! } printf("\n循环结束\n"); return 0; }运行结果:
1 2 3 4 5 循环结束我们来一步步看:
- 第 1 次:i=1,1<=5 为真 → 打印 1,i 变成 2
- 第 2 次:i=2,2<=5 为真 → 打印 2,i 变成 3
- 第 3 次:i=3,3<=5 为真 → 打印 3,i 变成 4
- 第 4 次:i=4,4<=5 为真 → 打印 4,i 变成 5
- 第 5 次:i=5,5<=5 为真 → 打印 5,i 变成 6
- 第 6 次:i=6,6<=5 为假 → 结束循环
完美,正好执行 5 次。
2.3 再看一个例子:计算 1 加到 100 的和
#include <stdio.h> int main() { int i = 1; // 循环变量,从1开始 int sum = 0; // 累加器,初始为0 while (i <= 100) { sum = sum + i; // 把i加到sum里 i++; // i加1 } printf("1+2+...+100 = %d\n", sum); return 0; }运行结果:
1+2+...+100 = 5050经典的高斯求和问题,用循环几行代码就搞定了。
2.4 死循环
⚠️新手必踩坑:死循环!
如果循环条件永远为真,循环就永远停不下来,这叫死循环。
while (1) { printf("停不下来啦!\n"); }或者更隐蔽的:
int i = 1; while (i <= 5) { printf("%d\n", i); // 忘了写 i++!i永远是1,条件永远为真 }死循环会让程序一直跑,直到你强制关掉它。写循环的时候一定要检查:循环变量有没有更新?条件会不会最终变成假?
💡小技巧:写 while 循环的时候,建议按 "初始值→条件→更新" 三步走,先把这三个要素都想清楚再写代码,能有效避免死循环。
三、do-while 循环
do-while是while的变体,区别是:先执行,后判断。
3.1 基本语法
do { // 循环体:先执行一次 } while (条件); // 注意!这里有个分号!执行流程:
- 先执行一次循环体
- 再判断条件
- 如果条件为真,继续循环
- 如果条件为假,结束循环
特点:先执行,后判断。循环体至少执行一次。
3.2 和 while 的对比
来看一个直观的对比:
while 循环(先判断):
int i = 10; while (i < 5) // 一开始就是假 { printf("%d\n", i); i++; } // 一次都不执行,什么也不输出do-while 循环(先执行):
int i = 10; do { printf("%d\n", i); // 先执行一次 i++; } while (i < 5); // 再判断,是假的,结束 // 输出:10看到区别了吗?即使条件一开始就是假的,do-while也会执行一次循环体。
3.3 do-while 的适用场景
do-while用得比while少,但在某些场景下特别合适,比如菜单程序:
#include <stdio.h> int main() { int choice; do { // 先显示菜单 printf("===== 菜单 =====\n"); printf("1. 开始游戏\n"); printf("2. 设置\n"); printf("3. 退出\n"); printf("请选择:"); scanf("%d", &choice); // 根据选择做不同的事 switch (choice) { case 1: printf("游戏开始!\n"); break; case 2: printf("进入设置\n"); break; case 3: printf("再见!\n"); break; default: printf("输入错误,请重新选择\n"); break; } } while (choice != 3); // 选3就退出 return 0; }菜单程序的特点是:至少要显示一次菜单让用户选,所以用do-while就很合适。
⚠️注意:
do-while最后的while后面有个分号!很多新手会忘写,或者写成和 while 一样的格式,导致编译错误。
四、for 循环
for是 C 语言里最常用、最灵活的循环,没有之一。
4.1 基本语法
for (表达式1; 表达式2; 表达式3) { // 循环体 }三个表达式分别是:
- 表达式 1:初始化,循环开始前执行一次
- 表达式 2:条件判断,每次循环前都判断
- 表达式 3:更新,每次循环体执行完后执行
对应的就是循环三要素:
- 表达式 1 → 初始值
- 表达式 2 → 条件
- 表达式 3 → 更新
4.2 执行流程
① 执行表达式1(只执行一次) ↓ ② 判断表达式2 ↓ ┌─ 为真 → ③ 执行循环体 │ ↓ │ ④ 执行表达式3 │ ↓ └── 回到第②步 ↓ 为假 → 结束循环文字描述有点绕,来看个例子就懂了。
4.3 第一个例子:打印 1 到 5
#include <stdio.h> int main() { int i; for (i = 1; i <= 5; i++) // ①初始 ②条件 ③更新 { printf("%d ", i); } printf("\n循环结束\n"); return 0; }运行结果:
1 2 3 4 5 循环结束和之前 while 的例子结果一样,但代码更紧凑了 —— 把循环三要素都写在了一行里,一目了然。
我们来一步步走:
- 先执行
i = 1(只执行一次) - 判断
i <= 5→ 1<=5 为真 → 执行循环体,打印 1 - 执行
i++→ i 变成 2 - 判断
i <= 5→ 2<=5 为真 → 执行循环体,打印 2 - 执行
i++→ i 变成 3 - …… 以此类推,直到 i=6 时条件为假,结束
是不是很清晰?
4.4 再看一个例子:计算 1 加到 100
#include <stdio.h> int main() { int i; int sum = 0; for (i = 1; i <= 100; i++) { sum += i; } printf("1+2+...+100 = %d\n", sum); return 0; }运行结果:
1+2+...+100 = 5050和 while 版本功能一样,但代码更简洁,循环变量的初始化、条件、更新都集中在一起,看着就舒服。
4.5 for 循环的各种变体
for循环非常灵活,三个表达式都可以省略(但分号不能省):
变体 1:省略表达式 1
如果循环变量已经初始化过了,可以省略表达式 1:
int i = 1; for (; i <= 5; i++) // 第一个表达式空着,但分号不能省 { printf("%d ", i); }变体 2:省略表达式 3
如果更新操作写在循环体里了,可以省略表达式 3:
for (i = 1; i <= 5; ) { printf("%d ", i); i++; // 更新写在这里 }变体 3:三个都省略
三个都省略的话,就变成死循环了:
for (;;) // 相当于 while(1) { printf("死循环\n"); }变体 4:C99 可以在 for 里定义变量
C99 标准允许在for的表达式 1 里直接定义变量:
for (int i = 1; i <= 5; i++) // 直接在for里定义i { printf("%d ", i); }这样写更方便,而且变量i的作用域只在for循环里面,外面用不了 —— 更安全。
💡建议:如果编译器支持 C99(现在基本都支持),推荐在
for里面直接定义循环变量,代码更简洁,作用域也更清晰。
五、三种循环怎么选?
三种循环都能实现循环功能,什么时候用哪个?
| 循环 | 特点 | 适用场景 |
|---|---|---|
while | 先判断,后执行 | 不知道循环次数,靠条件控制 |
do-while | 先执行,后判断,至少一次 | 菜单、输入验证等需要先执行一次的 |
for | 最灵活,三要素集中 | 知道循环次数,或者有明确的循环变量 |
简单记:
- 知道循环多少次 → 优先用for
- 不知道多少次,靠条件判断 → 用while
- 至少要执行一次 → 用do-while
其实用多了你会发现,for能搞定绝大多数场景,是当之无愧的 "循环一哥"。
六、break 和 continue
循环里还有两个重要的关键字:break和continue,用来 "打乱" 正常的循环流程。
6.1 break:跳出整个循环
break的作用是立即跳出当前循环,循环就结束了。
#include <stdio.h> int main() { int i; for (i = 1; i <= 10; i++) { if (i == 5) { break; // 遇到5就跳出循环 } printf("%d ", i); } printf("\n循环结束,i = %d\n", i); return 0; }运行结果:
1 2 3 4 循环结束,i = 5本来要循环到 10 的,但是 i 等于 5 的时候遇到了break,直接跳出了循环,后面的 5、6、7... 都不执行了。
💡注意:
break只能跳出一层循环。如果是嵌套循环,内层的 break 只能跳出内层,跳不到外层。
6.2 continue:跳过本次循环
continue的作用是跳过本次循环的剩余部分,直接进入下一次循环。
#include <stdio.h> int main() { int i; for (i = 1; i <= 10; i++) { if (i % 2 == 0) { continue; // 偶数就跳过,不打印 } printf("%d ", i); } printf("\n循环结束\n"); return 0; }运行结果:
1 3 5 7 9 循环结束遇到偶数的时候,continue跳过了后面的printf,直接进入下一次循环。所以只打印了奇数。
6.3 break 和 continue 的区别
| 关键字 | 作用 | 影响范围 |
|---|---|---|
break | 跳出整个循环 | 循环直接结束 |
continue | 跳过本次,继续下一次 | 只影响当前这一次 |
简单记:
- break= "不干了,下班!" → 整个循环结束
- continue= "这次跳过,下次继续!" → 只跳过这一轮
七、循环嵌套
循环里面还可以再写循环,这叫循环嵌套。
最经典的例子就是九九乘法表:
#include <stdio.h> int main() { int i, j; for (i = 1; i <= 9; i++) // 外层循环:控制行 { for (j = 1; j <= i; j++) // 内层循环:控制列 { printf("%d×%d=%-2d ", j, i, i * j); } printf("\n"); // 一行打完了,换行 } return 0; }运行结果:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 4×4=16 ...嵌套循环的执行逻辑
外层循环走一次,内层循环要走完整的一轮。
就像时钟:
- 外层 = 分针
- 内层 = 秒针
- 分针走一格,秒针要走一圈
九九乘法表中:
- i=1 时,j 从 1 到 1 → 打 1 个式子
- i=2 时,j 从 1 到 2 → 打 2 个式子
- i=3 时,j 从 1 到 3 → 打 3 个式子
- ...
- i=9 时,j 从 1 到 9 → 打 9 个式子
总共执行了 1+2+3+...+9 = 45 次内层循环体。
💡注意:嵌套循环的效率是 "相乘" 的关系。外层 100 次,内层 100 次,总共就是 10000 次。所以嵌套层数不要太多,一般 2-3 层就够了,再多程序就会变慢。
八、综合示例
学了这么多,让我们来看几个经典的循环练习。
示例 1:判断素数
#include <stdio.h> int main() { int n; int i; int is_prime = 1; // 假设是素数,1表示是,0表示不是 printf("请输入一个正整数:"); scanf("%d", &n); if (n < 2) { printf("%d不是素数\n", n); return 0; } // 从2试到n-1,看有没有能整除的 for (i = 2; i < n; i++) { if (n % i == 0) { is_prime = 0; // 找到了能整除的,不是素数 break; // 找到了就不用再试了,直接跳出 } } if (is_prime) { printf("%d是素数\n", n); } else { printf("%d不是素数\n", n); } return 0; }示例 2:打印三角形
#include <stdio.h> int main() { int n = 5; // 打印5行 int i, j; for (i = 1; i <= n; i++) // 外层:行 { // 先打空格 for (j = 1; j <= n - i; j++) { printf(" "); } // 再打星号 for (j = 1; j <= 2 * i - 1; j++) { printf("*"); } printf("\n"); } return 0; }运行结果:
* *** ***** ******* *********九、本节小结
本节我们学习了 C 语言的三种循环结构,以及两个循环控制关键字:
1. 三种循环
表格
| 循环 | 语法 | 特点 |
|---|---|---|
| while | while(条件) { ... } | 先判断,后执行;可能一次都不执行 |
| do-while | do { ... } while(条件); | 先执行,后判断;至少执行一次 |
| for | for(初始; 条件; 更新) { ... } | 最灵活,三要素集中;最常用 |
2. 循环三要素
- 初始值:从哪里开始
- 条件判断:什么时候结束
- 更新:每次改变什么
- ⚠️ 三者缺一不可,否则容易死循环
3. break 和 continue
- break:跳出整个循环,不干了
- continue:跳过本次,继续下一次
4. 循环嵌套
- 循环里面套循环
- 外层走一次,内层走一轮
- 注意嵌套不要太深,影响效率
📌学习建议:循环是编程的基本功中的基本功,一定要多练。建议你把经典的循环题都做一遍:打印各种图形、求和、求阶乘、判断素数、斐波那契数列…… 练到随手就能写出来,才算真正掌握了。
⚠️ 关于本文
由于笔者水平有限,文中难免存在疏漏、错误或表述不够准确的地方。如果你在阅读过程中发现了任何问题 —— 无论是概念错误、代码 bug、还是表述不清 —— 都欢迎在评论区留言指正,我会及时修正。
技术之路,道阻且长,行则将至。我们互相学习,共同进步 💪