有些逻辑需要反复执行。比如连续打印多次、累加一百个数字,如果手动复制粘贴代码,显然很低效。用好循环之后,打印三行和打印一千行,代码体量相差无几,区别仅仅在于是否使用循环结构。C 语言提供三种循环:forwhiledo-while

for 循环:三个动作一屏装下

for 把三件事捆在一起:初始化计数器、检查有没有到头、推进计数器。典型的例子是打印 0 到 9:

int i;
for (i = 0; i < 10; i++) {
    printf("%d\n", i);
}

拆开看执行顺序:

① i = 0      ,初始化,只跑这一次
② i < 10     ,检查条件,不成立就退出循环
③ printf     ,执行循环体
④ i++        ,计数器加一,回到 ②

所以这段打印 10 个数(0 到 9)。i 就是循环里最常见的迭代器变量。也可以一口气在 for 里声明(新版标准支持):for (int i = 0; i < 10; i++)

用 for 遍历数组

for 最常见的搭档是数组,拿迭代器当下标,把数组从头走到尾:

C 语言 for 循环遍历数组求和示例运行
int array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
int i;

for (i = 0; i < 10; i++) {
    sum += array[i];
}
printf("数组的和是 %d\n", sum);   // 55

+= 换成 *=,就是求阶乘的雏形,学完这篇可以顺手练一练 10! 是多少。

while 循环:只写条件

while 比 for 功能少一截:它只有条件,初始化和推进都得自己写在循环体里:

int n = 0;
while (n < 10) {
    n++;
}

只要 n < 10 成立就一直转。如果你忘了让 n 变化,这个循环就永远出不去。

#include <stdio.h>

int main(void) {
    int i = 0;
    while (i <= 5) {          // 输出 1 到 6
        printf("%d ", i + 1);
        i++;                   // 让条件有机会结束
    }
    printf("\n");
    return 0;
}

do-while 循环:先干一次再检查

do-while 是先执行再判断,所以循环体至少会跑一次。适合先让用户输入,再判断合不合格这种场景:

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

注意结尾有分号 ;。三种循环怎么选:数清楚做几次用 for,次数不定但可能一次不做用 while,必须至少做一次用 do-while。

开始条件?循环体循环后代码结束

while 循环流程:先判断条件,为真进入循环体,跑完回到条件再判断

无限循环

条件永远为真的循环就是无限循环,通常是写错,但有些场合故意这么写:

while (1) { /* 永远转 */ }
for (;;) { /* 永远转 */ }

配合下面两个刹车语句,可以做出一直等,等到了就停的效果。

break 与 continue:两个刹车

所有循环类型都通用的两个指令:

  • break;,立刻结束整个循环。
  • continue;,跳过本次循环剩余语句,直接进下一轮。

break 的经典用法:明明写的是无限循环,数到 10 就停:

int n = 0;
while (1) {
    n++;
    if (n == 10) {
        break;      // 到这里就跳出循环
    }
}

continue 的经典用法:只打印偶数。注意 continue 跳过了打印,奇数永远轮不到,但 n++ 在 continue 之前执行,所以不会卡死:

int n = 0;
while (n < 10) {
    n++;
    if (n % 2 == 1) {
        continue;                       // 回到 while 开头重新判断
    }
    printf("偶数:%d\n", n);            // 只有 n 为偶数才会走到这
}

嵌套循环

循环里套循环,外层每走一步,内层完整跑一圈。两个 for 就能打出乘法口诀表:

for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        printf("%d×%d=%-2d  ", j, i, j * i);
    }
    printf("\n");
}

脑内推一遍:i=1 时内层只跑 j=1i=2 时内层跑 j=1j=2;于是每行长度刚好等于行号。

死循环排查

程序运行卡死,绝大多数情况都是死循环。排查可以遵循这个思路:循环条件能否发生变化?循环体内有没有代码推动条件走向终止?小心 continue 意外跳过计数器更新语句。另外 for(;;)while(1) 这类无限循环,如果缺少对应的 break,也是非常常见的失误。