C 控制流

程序默认是从上到下顺序执行的,但真实世界的逻辑需要"做判断"和"重复执行"。控制流语句就是用来改变执行顺序的——条件分支(if/switch)让程序学会做选择,循环(for/while)让程序学会重复干活。本篇覆盖 C 全部控制流。

一、if / else 条件分支

if 是最基本的判断语句,根据条件真假选择执行哪段代码:

#include <stdio.h>

int main(void) {
    int score = 85;

    // 1. 基本 if
    if (score >= 60) {
        printf("及格了\n");
    }

    // 2. if-else
    if (score >= 90) {
        printf("优秀\n");
    } else {
        printf("继续努力\n");
    }

    // 3. if-else if-else(多分支)
    if (score >= 90) {
        printf("A\n");
    } else if (score >= 80) {
        printf("B\n");
    } else if (score >= 70) {
        printf("C\n");
    } else if (score >= 60) {
        printf("D\n");
    } else {
        printf("F\n");
    }

    // 4. 单行可以省略花括号(但不推荐!)
    if (score > 0)
        printf("正数\n");   // 只有这一句属于 if

    // 5. 嵌套 if
    int age = 25;
    if (age >= 18) {
        if (age >= 65) {
            printf("老年人\n");
        } else {
            printf("成年人\n");
        }
    }
    return 0;
}

几个要点:

二、switch 多分支

当需要根据一个变量的多个不同值做不同事时,用 switch 比 if-else if 链更清晰:

#include <stdio.h>

int main(void) {
    int day = 3;

    // switch:多分支选择,适合"等于某值"的场景
    switch (day) {
        case 1:
            printf("星期一\n");
            break;            // break 不能漏!否则会"贯穿"
        case 2:
            printf("星期二\n");
            break;
        case 3:
            printf("星期三\n");
            break;
        case 4:
            printf("星期四\n");
            break;
        case 5:
            printf("星期五\n");
            break;
        case 6:
        case 7:                // 多个 case 共享代码
            printf("周末\n");
            break;
        default:               // 都不匹配时执行
            printf("无效\n");
    }
    // 输出: 星期三

    // 小心:漏 break 会"fall through"
    int x = 1;
    switch (x) {
        case 1: printf("一\n");   // 没有break
        case 2: printf("二\n");   // 会继续执行
        case 3: printf("三\n");   // 也会执行
    }
    // 输出: 一 二 三(贯穿了)
    return 0;
}

switch 的三条铁律:

有时候"贯穿"是故意的——比如让多个 case 共享同一段代码(示例里 case 6 和 case 7 都打印"周末")。这时候加注释说明是有意为之。

三、for 循环

for 循环是 C 里用得最多的循环,语法是 for (初始化; 条件; 更新),三部分用分号分隔:

#include <stdio.h>

int main(void) {
    // 1. 经典 for 循环
    for (int i = 0; i < 5; i++) {   // C99 起可以在 for 内声明 i
        printf("%d ", i);            // 0 1 2 3 4
    }
    printf("\n");

    // 2. 倒序
    for (int i = 5; i > 0; i--) {
        printf("%d ", i);            // 5 4 3 2 1
    }
    printf("\n");

    // 3. 步长为 2
    for (int i = 0; i <= 10; i += 2) {
        printf("%d ", i);            // 0 2 4 6 8 10
    }
    printf("\n");

    // 4. 嵌套循环(经典:九九乘法表)
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%-2d ", j, i, i*j);
        }
        printf("\n");
    }

    // 5. 省略某些部分
    int i = 0;
    for (; i < 3; ) {   // 等价于 while (i < 3)
        printf("%d ", i);
        i++;
    }
    return 0;
}

for 的执行顺序:初始化 → 条件判断 → 循环体 → 更新 → 条件判断 → 循环体 → 更新 → ...。三部分都可以省略(for (;;) 是死循环),但分号不能少。

四、while 与 do-while

while 循环适合"不确定循环多少次"的场景:

#include <stdio.h>

int main(void) {
    // 1. while:先判断后执行(可能一次都不执行)
    int i = 0;
    while (i < 5) {
        printf("%d ", i);   // 0 1 2 3 4
        i++;
    }
    printf("\n");

    // while 最适合"不知道循环多少次"的场景
    int n = 1024;
    int count = 0;
    while (n > 1) {
        n /= 2;
        count++;
    }
    printf("log2 = %d\n", count);   // 10

    // 2. do-while:先执行后判断(至少执行一次)
    int num = 0;
    do {
        printf("num = %d\n", num);
        num++;
    } while (num < 0);   // 条件为假,但循环体已执行了一次

    // 经典用法:菜单循环(至少展示一次菜单)
    int choice;
    do {
        printf("1. 开始  2. 设置  0. 退出\n");
        printf("请选择:");
        scanf("%d", &choice);
    } while (choice != 0);
    return 0;
}

while 和 do-while 的区别:

经典场景:菜单循环(至少展示一次菜单)、输入验证(至少读一次输入)。

五、break 与 continue

这两个关键字用来改变循环的正常流程:

#include <stdio.h>

int main(void) {
    // break:跳出当前循环
    for (int i = 0; i < 10; i++) {
        if (i == 5) {
            break;          // i=5 时整个循环结束
        }
        printf("%d ", i);   // 0 1 2 3 4
    }
    printf("\n---\n");

    // continue:跳过本次,进入下一次
    for (int i = 0; i < 10; i++) {
        if (i % 2 == 0) {
            continue;       // 偶数跳过
        }
        printf("%d ", i);   // 1 3 5 7 9
    }
    printf("\n---\n");

    // break 只跳一层:嵌套循环时只跳出内层
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (j == 1) break;     // 只跳出内层 for
            printf("%d-%d ", i, j);
        }
    }
    // 输出: 0-0 1-0 2-0
    printf("\n");

    // 想一次跳出多层?用 goto(少有的合理用法)
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (i == 1 && j == 1) goto done;
        }
    }
    done:
    printf("跳出多层循环\n");
    return 0;
}

六、goto(谨慎使用)

goto 可以无条件跳转到指定标签,几乎所有编程书都告诫"不要用 goto"——它会让代码变成"意大利面条",难以追踪。但 C 里有两个场景用 goto 反而更清晰:

#include <stdio.h>

int main(void) {
    // goto:无条件跳转,几乎不推荐用!
    // 唯一合理的两个场景:

    // 场景1:跳出多层嵌套循环
    int found = 0;
    for (int i = 0; i < 10 && !found; i++) {
        for (int j = 0; j < 10; j++) {
            if (i * j == 42) {
                printf("找到: %d*%d\n", i, j);
                found = 1;
                goto cleanup;   // 跳出多层
            }
        }
    }
    cleanup:
    printf("清理资源\n");

    // 场景2:集中错误处理(类似 try-catch)
    FILE *fp = NULL;
    char *buf = NULL;

    fp = fopen("x.txt", "r");
    if (fp == NULL) goto error;

    buf = malloc(100);
    if (buf == NULL) goto error;

    // 正常逻辑...
    free(buf);
    fclose(fp);
    return 0;

    error:
    if (buf) free(buf);
    if (fp) fclose(fp);
    return 1;
}

除此之外坚决不要用 goto——尤其不要用 goto 往回跳(模拟循环),那是上世纪 70 年代的写法。

七、循环选择指南

小结

if-else 做条件判断,switch 做多值选择(记得 break),for/while/do-while 做循环,break 跳出、continue 跳过,goto 仅用于跳出多层或错误处理。下一篇我们看 C 的函数——把代码组织成可复用的单元。

← 上一篇 C 运算符

下一篇 C 函数

✈️💬