编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • C语言入门精通

    • 入门教程

      • README
      • 基础语法
      • 数据类型
      • 运算符
      • 循环和选择
        • 4.2 选择结构
          • 4.2.1 if语句
          • 4.2.2 if-else语句
          • 4.2.3 多条件语句
          • 4.2.4 switch语句
          • 4.2.5 嵌套选择结构
          • 4.2.6 三元运算符
          • 4.2.7 注意事项说明
          • 4.2.8 综合示例
          • 4.2.9 综合案例与思考
        • 4.3 循环结构
          • 4.3.1 for循环
          • 4.3.2 while循环
          • 4.3.3 do-while循环
          • 4.3.4 嵌套循环
          • 4.3.5 无限循环
          • 4.3.6 循环注意事项
          • 4.3.7 综合案例与思考
        • 4.4 跳出循环
          • 4.4.1 break语句
          • 4.4.2 continue语句
          • 4.4.3 goto语句
          • 4.4.4 综合案例与思考
      • 输入输出
      • 函数
      • 指针
      • 数组和容器
      • 类和内存
      • 流与文件
      • 结构体
      • 线程和锁
      • 预处理器
      • 高级数据
    • 综合案例

    • 专栏博客

    • 标准集库

  • Cpp入门到精通

  • Java入门精通

  • Go入门到精通

  • JavaScript入门

  • CodeX
  • C语言入门精通
  • 入门教程
杨充
2025-07-21
目录

循环和选择

# 04.循环和选择

# 目录介绍

  • 4.1 语句和程序块
  • 4.2 选择结构
    • 4.2.1 if语句
    • 4.2.2 if-else语句
    • 4.2.3 多条件语句
    • 4.2.4 switch语句
    • 4.2.5 嵌套选择结构
    • 4.2.6 三元运算符
    • 4.2.7 注意事项说明
    • 4.2.8 综合示例
    • 4.2.9 综合案例与思考
  • 4.3 循环结构
    • 4.3.1 for循环
    • 4.3.2 while循环
    • 4.3.3 do-while循环
    • 4.3.4 嵌套循环
    • 4.3.5 无限循环
    • 4.3.6 循环注意事项
    • 4.3.7 综合案例与思考
  • 4.4 跳出循环
    • 4.4.1 break语句
    • 4.4.2 continue语句
    • 4.4.3 goto语句
    • 4.4.4 综合案例与思考

# 4.2 选择结构

# 4.2.1 if语句

if 语句用于在条件为真时执行代码块。

语法

if (条件) {
    // 条件为真时执行的代码
}
1
2
3

示例

int age = 18;
if (age >= 18) {
    printf("You are an adult.\n");
}
1
2
3
4

# 4.2.2 if-else语句

if-else 语句用于在条件为真时执行一个代码块,否则执行另一个代码块。语法

if (条件) {
    // 条件为真时执行的代码
} else {
    // 条件为假时执行的代码
}
1
2
3
4
5

示例

int age = 16;
if (age >= 18) {
    printf("You are an adult.\n");
} else {
    printf("You are a minor.\n");
}
1
2
3
4
5
6

# 4.2.3 多条件语句

if-else if-else 语句用于处理多个条件。

语法

if (条件1) {
    // 条件1为真时执行的代码
} else if (条件2) {
    // 条件2为真时执行的代码
} else {
    // 所有条件为假时执行的代码
}
1
2
3
4
5
6
7

示例

int score = 85;
if (score >= 90) {
    printf("Grade: A\n");
} else if (score >= 80) {
    printf("Grade: B\n");
} else if (score >= 70) {
    printf("Grade: C\n");
} else {
    printf("Grade: F\n");
}
1
2
3
4
5
6
7
8
9
10

# 4.2.4 switch语句

switch 语句用于根据变量的值执行不同的代码块。

switch (表达式) {
    case 值1:
        // 表达式等于值1时执行的代码
        break;
    case 值2:
        // 表达式等于值2时执行的代码
        break;
    default:
        // 表达式不等于任何值时执行的代码
}
1
2
3
4
5
6
7
8
9
10

示例

int day = 3;
switch (day) {
    case 1:
        printf("Monday\n");
        break;
    case 2:
        printf("Tuesday\n");
        break;
    case 3:
        printf("Wednesday\n");
        break;
    default:
        printf("Invalid day\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意事项

  • switch 表达式必须是整型或字符型。
  • 每个 case 块通常以 break 结束,否则会继续执行下一个 case 块。
  • default 块是可选的,用于处理未匹配的情况。

# 4.2.5 嵌套选择结构

选择结构可以嵌套使用。示例

int age = 20;
char gender = 'M';

if (age >= 18) {
    if (gender == 'M') {
        printf("Adult male\n");
    } else {
        printf("Adult female\n");
    }
} else {
    printf("Minor\n");
}
1
2
3
4
5
6
7
8
9
10
11
12

# 4.2.6 三元运算符

三元运算符是一种简化的选择结构。语法

条件 ? 表达式1 : 表达式2;
1

示例

int age = 20;
char *status = (age >= 18) ? "Adult" : "Minor";
printf("%s\n", status);
1
2
3

# 4.2.7 注意事项说明

  1. 条件表达式: 条件表达式的结果必须是 true(非零)或 false(零)。
  2. if 和 else 的匹配**:else 总是与最近的 if 匹配。
  3. switch 的 break:如果忘记写 break,程序会继续执行下一个 case 块。
  4. 代码风格:使用大括号 {} 明确代码块的范围,即使只有一行代码。

# 4.2.8 综合示例

#include <stdio.h>

int main() {
    int score;
    printf("Enter your score: ");
    scanf("%d", &score);

    if (score >= 90) {
        printf("Grade: A\n");
    } else if (score >= 80) {
        printf("Grade: B\n");
    } else if (score >= 70) {
        printf("Grade: C\n");
    } else if (score >= 60) {
        printf("Grade: D\n");
    } else {
        printf("Grade: F\n");
    }

    char grade;
    switch (score / 10) {
        case 10:
        case 9:
            grade = 'A';
            break;
        case 8:
            grade = 'B';
            break;
        case 7:
            grade = 'C';
            break;
        case 6:
            grade = 'D';
            break;
        default:
            grade = 'F';
    }
    printf("Grade: %c\n", grade);

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 4.2.9 综合案例与思考

综合案例:用选择结构实现一个简单的计算器

#include <stdio.h>

int main() {
    double num1, num2;
    char operator;
    
    printf("输入表达式 (如 3.5 + 2.1): ");
    scanf("%lf %c %lf", &num1, &operator, &num2);
    
    switch (operator) {
        case '+':
            printf("%.2f + %.2f = %.2f\n", num1, num2, num1 + num2);
            break;
        case '-':
            printf("%.2f - %.2f = %.2f\n", num1, num2, num1 - num2);
            break;
        case '*':
            printf("%.2f * %.2f = %.2f\n", num1, num2, num1 * num2);
            break;
        case '/':
            if (num2 != 0) {
                printf("%.2f / %.2f = %.2f\n", num1, num2, num1 / num2);
            } else {
                printf("错误: 除数不能为0!\n");
            }
            break;
        default:
            printf("不支持的运算符: %c\n", operator);
    }
    
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

原理说明:if-else 适用于范围判断(如成绩等级),switch 适用于离散值判断(如菜单选项、运算符)。switch 底层通过跳转表(jump table)实现,当分支较多时效率高于连续的 if-else。break 在 switch 中必不可少,否则会发生"贯穿"(fall-through),继续执行下一个 case 的代码。

思考题:

  1. switch 语句中如果忘记写 break 会发生什么?这种"贯穿"特性在什么场景下有用?
  2. if-else 和 switch 各自适合什么场景?什么情况下不能用 switch 替代 if-else?
  3. 为什么 switch 的表达式必须是整数类型或字符型,不能是浮点型或字符串?

# 4.3 循环结构

在 C 语言中,循环结构用于重复执行一段代码,直到满足特定条件。C 语言提供了三种主要的循环结构:for 循环、while 循环和 do-while 循环。

# 4.3.1 for循环

for 循环用于在已知循环次数的情况下重复执行代码。

语法

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

执行流程

  1. 执行初始化语句。
  2. 检查条件是否为真:
    • 如果为真,执行循环体。
    • 如果为假,退出循环。
  3. 执行更新语句。
  4. 重复步骤 2 和 3。

示例

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

输出:

0 1 2 3 4
1

# 4.3.2 while循环

while 循环用于在条件为真时重复执行代码。

语法

while (条件) {
    // 循环体
}
1
2
3

执行流程

  1. 检查条件是否为真:
    • 如果为真,执行循环体。
    • 如果为假,退出循环。
  2. 重复步骤 1。

示例

int i = 0;
while (i < 5) {
    printf("%d ", i);
    i++;
}
1
2
3
4
5

输出:

0 1 2 3 4
1

# 4.3.3 do-while循环

do-while 循环先执行循环体,然后检查条件是否为真。

语法

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

执行流程

  1. 执行循环体。
  2. 检查条件是否为真:
    • 如果为真,重复步骤 1。
    • 如果为假,退出循环。

示例

int i = 0;
do {
    printf("%d ", i);
    i++;
} while (i < 5);
1
2
3
4
5

输出:

0 1 2 3 4
1

# 4.3.4 嵌套循环

循环可以嵌套使用,即在一个循环中包含另一个循环。

示例

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        printf("(%d, %d) ", i, j);
    }
    printf("\n");
}
1
2
3
4
5
6

输出:

(1, 1) (1, 2) (1, 3) 
(2, 1) (2, 2) (2, 3) 
(3, 1) (3, 2) (3, 3) 
1
2
3

# 4.3.5 无限循环

无限循环是指条件永远为真的循环,通常用于需要持续运行的程序。

示例

while (1) {
    printf("This is an infinite loop.\n");
}
1
2
3

# 4.3.6 循环注意事项

  1. 循环条件:确保循环条件最终会变为假,否则会导致无限循环。
  2. 循环变量:在 for 循环中,循环变量的作用域仅限于循环体。
  3. 代码风格:使用大括号 {} 明确循环体的范围,即使只有一行代码。
  4. 性能优化:避免在循环体内执行不必要的操作,以提高性能。

# 4.3.7 综合案例与思考

综合案例:用循环实现经典算法

#include <stdio.h>

int main() {
    // 案例1:求1~100的和(for循环)
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    printf("1~100的和: %d\n", sum);  // 5050
    
    // 案例2:猜数字游戏(while循环)
    int secret = 42;
    int guess = 0;
    int attempts = 0;
    printf("\n猜数字游戏(1-100),答案是42:\n");
    // 模拟猜测过程
    int guesses[] = {50, 25, 40, 45, 42};
    int idx = 0;
    while (guess != secret && idx < 5) {
        guess = guesses[idx++];
        attempts++;
        if (guess > secret) {
            printf("猜 %d - 太大了!\n", guess);
        } else if (guess < secret) {
            printf("猜 %d - 太小了!\n", guess);
        } else {
            printf("猜 %d - 恭喜,猜对了! 用了%d次\n", guess, attempts);
        }
    }
    
    // 案例3:打印九九乘法表(嵌套循环)
    printf("\n九九乘法表:\n");
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%-4d", j, i, i * j);
        }
        printf("\n");
    }
    
    // 案例4:do-while确保至少执行一次
    int input;
    do {
        input = 3;  // 模拟输入
        printf("\n输入的值: %d (do-while至少执行一次)\n", input);
    } while (input < 0);
    
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

原理说明:for 循环适合已知循环次数的场景;while 循环适合条件驱动的场景;do-while 保证循环体至少执行一次。嵌套循环的时间复杂度是各层循环次数的乘积,因此要注意性能。编译器会对简单循环进行优化(如循环展开),但复杂循环可能需要手动优化。

思考题:

  1. for、while、do-while 三种循环能否互相替换?什么场景下 do-while 比 while 更合适?
  2. 一个二重嵌套循环,外层循环100次,内层循环1000次。如果交换内外层,对性能有影响吗?
  3. 无限循环 while(1) 和 for(;;) 有区别吗?在实际编程中什么场景需要无限循环?

# 4.4 跳出循环

# 4.4.1 break语句

break 语句用于立即退出循环。

示例

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;
    }
    printf("%d ", i);
}
1
2
3
4
5
6

输出:

0 1 2 3 4
1

# 4.4.2 continue语句

continue 语句用于跳过当前循环的剩余部分,直接进入下一次循环。

示例

for (int i = 0; i < 5; i++) {
    if (i == 2) {
        continue;
    }
    printf("%d ", i);
}
1
2
3
4
5
6

# 4.4.3 goto语句

goto 语句用于无条件跳转到程序中指定的标签位置。虽然 goto 在大多数场景中不推荐使用(会破坏结构化编程),但在某些特定场景下非常有用,如多层嵌套循环的跳出和错误处理时的资源清理。

语法

goto 标签名;
// ...
标签名:
    // 跳转到此处执行
1
2
3
4

示例:跳出多层嵌套循环

#include <stdio.h>

int main() {
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (i == 2 && j == 3) {
                goto end_loops;
            }
            printf("(%d,%d) ", i, j);
        }
        printf("\n");
    }
end_loops:
    printf("\n跳出多层循环,在i=2,j=3处退出\n");
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

示例:错误处理中的资源清理

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file = fopen("test.txt", "r");
    if (file == NULL) goto cleanup;
    
    int *buffer = (int *)malloc(100 * sizeof(int));
    if (buffer == NULL) goto cleanup_file;
    
    // 正常处理逻辑...
    printf("资源分配成功\n");
    
    free(buffer);
    fclose(file);
    return 0;

cleanup_file:
    fclose(file);
cleanup:
    printf("资源分配失败,已清理\n");
    return 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

原理说明:goto 的本质是汇编语言中的无条件跳转指令(JMP)。C语言是结构化编程语言,过度使用 goto 会导致"面条代码"(spaghetti code),难以维护。但在Linux内核源码中,goto 被广泛用于错误处理路径,因为它能避免深层嵌套的 if-else,使错误清理逻辑更清晰。

# 4.4.4 综合案例与思考

综合案例:流程控制语句的综合运用

#include <stdio.h>

int main() {
    // 案例1:break跳出循环 - 查找第一个能被7整除的数
    printf("案例1:查找1~100中第一个能被7整除的数\n");
    for (int i = 1; i <= 100; i++) {
        if (i % 7 == 0) {
            printf("找到: %d\n", i);
            break;
        }
    }
    
    // 案例2:continue跳过 - 打印1~20中的奇数
    printf("\n案例2:1~20中的奇数: ");
    for (int i = 1; i <= 20; i++) {
        if (i % 2 == 0) {
            continue;
        }
        printf("%d ", i);
    }
    printf("\n");
    
    // 案例3:break跳出内层循环 - 查找素数
    printf("\n案例3:2~50中的素数: ");
    for (int i = 2; i <= 50; i++) {
        int is_prime = 1;
        for (int j = 2; j * j <= i; j++) {
            if (i % j == 0) {
                is_prime = 0;
                break;  // 只跳出内层循环
            }
        }
        if (is_prime) {
            printf("%d ", i);
        }
    }
    printf("\n");
    
    // 案例4:goto跳出多层嵌套 - 在二维数组中查找目标值
    printf("\n案例4:在矩阵中查找目标值25\n");
    int matrix[5][5];
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            matrix[i][j] = i * 10 + j * 3;
    
    int target = 25;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (matrix[i][j] == target) {
                printf("找到 %d 在位置 [%d][%d]\n", target, i, j);
                goto found;
            }
        }
    }
    printf("未找到 %d\n", target);
found:
    
    // 案例5:综合运用 - 模拟密码验证(最多3次机会)
    printf("\n案例5:密码验证(模拟)\n");
    int correct_pin = 1234;
    int pins[] = {1111, 5678, 1234};  // 模拟输入
    int max_attempts = 3;
    for (int i = 0; i < max_attempts; i++) {
        printf("第%d次尝试: %d ", i + 1, pins[i]);
        if (pins[i] == correct_pin) {
            printf("- 验证成功!\n");
            break;
        }
        printf("- 密码错误\n");
        if (i == max_attempts - 1) {
            printf("已达最大尝试次数,账户锁定!\n");
        }
    }
    
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

原理说明:break 只能跳出当前所在的最内层循环或 switch 语句,无法直接跳出多层嵌套。continue 只跳过当前迭代的剩余代码,不会影响外层循环。当需要跳出多层嵌套循环时,有三种方案:1)使用标志变量逐层判断;2)将嵌套循环封装为函数,用 return 跳出;3)使用 goto(在C语言中最简洁)。编译器处理 break 和 continue 时,会将它们转化为条件跳转指令。

思考题:

  1. break 在 for 循环和 switch 语句中的行为有什么不同?如果 switch 嵌套在 for 中,break 跳出哪个?
  2. 不使用 goto,如何优雅地跳出三层嵌套循环?请写出至少两种方案。
  3. Linux内核源码中大量使用 goto 进行错误处理,这与"不要使用goto"的编程建议矛盾吗?你怎么看?
上次更新: 2026/06/10, 11:13:41
运算符
输入输出

← 运算符 输入输出→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式