9. 重复是力量:C语言循环结构

前几篇文章,我们让程序有了记忆(变量),会说话(输入输出),还学会了判断(分支)。但程序还有一个让人类望尘莫及的本事:不知疲倦地重复做一件事。

想想看,让你把“你好”写 100 遍,你可能会烦;但程序用一个循环,不到一毫秒就能完成。循环是计算机真正的效率利器,它能把几行代码的执行次数放大成千上万倍。

C 语言给了你三把循环的工具:whiledo-whilefor,外加两个控制循环走向的关键字 breakcontinue。今天我们就来掌握它们。


一、while 循环:先问再做

while 循环的逻辑最简单:只要条件成立,就重复执行循环体。每次执行前都会先检查条件,如果一开始就不成立,循环体一次都不会执行。

while (条件) {
    // 循环体
}

一个最经典的例子——从 1 数到 5:

#include <stdio.h>

int main(void) {
    int i = 1;                  // 初始化
    while (i <= 5) {            // 条件
        printf("%d ", i);
        i++;                    // 更新循环变量
    }
    printf("\n");
    return 0;
}

输出:

1 2 3 4 5

如果把 i++ 忘掉,i 永远是 1,条件永远成立,程序就会陷入无限循环。写 while 循环时,一定问自己三个问题:

  • 循环变量初始化了没有?
  • 条件最终会不会变成假?
  • 每次循环有没有朝“假”的方向前进一步?

这三个问题是防止死循环的“三把锁”。


二、do-while 循环:先做再问

while 的变体,它把条件检查挪到了循环体之后。这意味着不管条件如何,循环体至少执行一次

do {
    // 循环体
} while (条件);

注意:while (条件); 后面的分号不能少——这是初学者最容易掉的坑之一。

一个典型的场景:要求用户输入一个正数,不合法就一直提示重新输入。

#include <stdio.h>

int main(void) {
    int number;
    do {
        printf("请输入一个正数:");
        scanf("%d", &number);
    } while (number <= 0);

    printf("你输入了 %d,谢谢!\n", number);
    return 0;
}

用户的输入在循环体里读,然后再判断。因为“读”的动作必须先执行一次,所以用 do-whilewhile 更自然。


三、for 循环:最紧凑的循环体

大多数循环都有三步曲:初始化、条件检查、更新循环变量。for 循环把它们一行搞定,让代码紧凑易读。

for (初始化; 条件; 更新) {
    // 循环体
}

执行顺序是:

  1. 执行初始化(只执行一次)
  2. 检查条件,如果为假则退出循环
  3. 执行循环体
  4. 执行更新
  5. 跳回第 2 步

for 重写 1 到 5 的计数:

for (int i = 1; i <= 5; i++) {
    printf("%d ", i);
}

括号里三个部分都可以省略(分号必须保留),但省略要有充足理由。比如:

  • for (; i < 10; i++):初始化放到外面
  • for (;;):无限循环(等价于 while(1)

for 循环里声明的变量(如 int i)在 C99 标准中是允许的,作用域仅限于循环内。如果你的编译器比较老(如某些 C89 模式),可能需要把变量声明提到循环外。


四、breakcontinue:循环的半路控制

有时候循环不必傻傻跑到条件变为假,可以在中途就跳出,或者跳过剩下的部分直接开始下一轮。这就需要 breakcontinue

break:直接跳出循环

for (int i = 1; i <= 10; i++) {
    if (i == 5) {
        break;    // 碰到 5 就终止整个循环
    }
    printf("%d ", i);
}

输出:1 2 3 4(i=5 时直接跳出,后面的 6-10 都不打)

continue:跳过本轮剩余部分,进入下一轮

for (int i = 1; i <= 5; i++) {
    if (i == 3) {
        continue; // 跳过 i=3 时的打印,直接去 i++
    }
    printf("%d ", i);
}

输出:1 2 4 5(3 被跳过了)

注意:在 whiledo-while 里用 continue 要特别小心——它会跳转到条件检查处,可能导致更新语句被跳过而形成死循环。比如:

int i = 0;
while (i < 5) {
    if (i == 2) continue;
    printf("%d ", i);
    i++;  // 当 i=2 时 continue,i++ 被跳过,永远停在 2,死循环
}

所以在 while 里用 continue,要确保变量的更新发生在 continue 之前。


五、嵌套循环与经典案例:九九乘法表

循环里面可以再套循环,形成嵌套循环。外循环每执行一次,内循环就会完整地跑一遍。它常用来处理二维表格、矩阵、图形打印等问题。

一个最典型的例子:打印九九乘法表。

#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 9; i++) {          // 外循环控制行
        for (int j = 1; j <= i; j++) {      // 内循环控制列,注意 j <= i 形成下三角
            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 
...
1×9=9  2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81 

%-2d 表示左对齐占 2 个宽度,让排版整齐。试试把 j <= i 改成 j <= 9,你就会看到完整的矩形表,而不仅仅是下三角。

嵌套循环时注意:内循环变量和外循环变量不要用同一个名字(除非你非常清楚作用域规则),不然内层的修改会干扰外层。


六、三大循环的选择指南

场景推荐原因
循环次数已知(如遍历数组)for初始、条件、更新集中,清晰
循环次数未知,先判断再执行while条件在最前面,符合直觉
循环次数未知,至少执行一次do-while体在条件前,保证首次执行

实际使用中,forwhile 可以互相转换,大多数场景用 for 就能胜任。但当你需要先读数据再判断是否继续时,do-while 就展现出它的优势。


七、常见错误与陷阱

  1. while 后多加分号

    int i = 0;
    while (i < 5); {   // 分号让循环体变成空的,死循环
        printf("%d", i);
        i++;
    }
    
  2. do-while 后忘分号
    do { ... } while (cond) 末尾必须带分号。

  3. 循环变量忘记更新
    while 体内缺少 i++,导致死循环。

  4. for 括号里用逗号替代分号
    for (int i = 0, i < 10, i++) 错误,分号必须保留。

  5. while/do-while 中用 continue 导致更新跳过
    如前例,务必先更新再 continue,或者改用 for 循环。

  6. 循环边界错误
    比如 i <= 10 写成 i < 10,会少一次。初学者要仔细检查边界。


八、小结

循环让程序有了重复执行的能力,结合之前学的变量和分支,你已经可以写出有逻辑的、能处理批量数据的小程序了。whiledo-whilefor 各有适用的场合,breakcontinue 给了你更精细的控制。嵌套循环则打开了处理二维问题的大门。

但很快你会面临一个新问题:如果我想存一个班所有学生的成绩,难道要声明 score1score2……score50 这样 50 个变量吗?那显然太蠢了。下一篇文章,我们就迎来一个重要的新工具——数组,它能让你用一个名字管理一串数据,让程序处理大量数据变得轻而易举。


课后小练习

  1. while 循环计算 1 到 100 的累加和并输出。
  2. for 循环打印斐波那契数列的前 20 项(1, 1, 2, 3, 5, 8…),每行输出 5 个数。
  3. 用嵌套循环打印如下图形:
    *
    **
    ***
    ****
    *****
    
  4. 写一个猜数字游戏:程序预设一个 1-100 的整数(可以先固定写死一个值),让用户猜,每次猜完提示“大了”或“小了”,直到猜中为止。统计猜了多少次。用 do-whilewhile 实现。

题外话
如果你正在学C语言或计划学C语言,请订阅免费专栏《C语言:从入门到精通》。这是一个循序渐进的 C 语言博客系列,从最基础的环境搭建一路到高阶的系统编程技巧,帮你构建一个完整的知识体系。不需要积分,不需要VIP!

我们下期见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值