← 返回文章列表

C 语言(三)|分支与循环:让程序拥有判断与重复执行能力

详细介绍C语言分支语句和循环语句,包括if、switch、while、do-while、for等核心知识点。

版权声明:本文为作者原创,版权归作者所有。如需转载或引用,请联系作者获得授权,并在使用时注明出处。

在C语言的世界里,也并不是一帆风顺的走直线,其代码运行往往需要判断或是循环,才能达到程序想要的结果。分支语句和循环语句就是实现这些功能必不可少的工具。今天,我将结合我的学习过程,谈谈自己的理解。

一、分支语句让程序"做选择"

分支语句的作用是 "根据条件判断,执行不同代码块",在我们生活中,我们会根据不同的情况,做出不同的选择和规划,分支语句在C语言中也是如此。C语言中常用的分支语句有两种:if语句和switch语句。

1.1 if语句:最灵活的条件判断

if语句是C语言中最基础的分支语句,它能处理从简单到复杂的各种条件判断。其基本语法分为三种形式,我举例讨论其形式与用法。

(1)单分支:满足条件才执行

当我们只需要 "满足条件就做某事,不满足就跳过" 时,使用单分支if语句。

语法格式:

if (条件表达式)
{
    // 条件为真(非0)时执行的代码块
}
// 条件为假(0)时,直接执行此处代码

注意:if后的括号()不可省略,括号内的 "条件表达式" 结果为 "真(非 0)" 或 "假(0)"。如果代码块只有 1 行,大括号{}可以省略,但为了代码可读性,建议始终加上。

实例:判断一个数是否为正数:

#include <stdio.h>
int main() 
{
    int num = 10;
    if (num > 0) // 条件:num大于0
    {
        printf("%d是正数\n", num); // 条件为真,执行此句
    }
    printf("判断结束\n"); // 无论条件真假,都会执行此句
    return 0;
}

运行结果:10是正数 → 判断结束

(2)双分支:二选一的判断

当需要 "满足条件做 A,不满足做 B" 时,使用if-else双分支语句。

语法格式:

if (条件表达式) {
    // 条件为真时执行的代码块A
} else {
    // 条件为假时执行的代码块B
}

实例:判断是否为闰年:

#include<stdio.h>
int main()
{
    int i = 0;
    scanf("%d", &i);
    if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0))
        printf("Yes"); // 条件满足,执行此语句
    else
        printf("No"); // 不满足条件,就执行此语句
    return 0;
}

闰年的判断方式:

  1. 能被4整除,但不能被100整除
  2. 能被400整除

逻辑运算符说明:

  • &&(逻辑与):相当于生活中的 "并且",要求两个条件同时为真,整体结果才为真;只要有一个条件为假,整体结果就为假。
  • ||(逻辑或):相当于生活中的 "或者",要求两个条件至少有一个为真,整体结果就为真;只有两个条件都为假时,整体结果才为假。

(3)多分支:多种情况的判断

当需要处理 "多个条件,对应不同执行逻辑" 时,使用if-else if-else多分支语句。

语法格式:

if (条件1) {
    // 条件1为真时执行
} else if (条件2) {
    // 条件1为假、条件2为真时执行
} else if (条件3) {
    // 前两个条件为假、条件3为真时执行
} else {
    // 所有条件都为假时执行(可选)
}

关键规则:程序会从 "条件 1" 开始依次判断,只要遇到第一个为真的条件,就执行对应的代码块,后续条件不再判断。

实例:根据分数划分等级(90+为A,80-89为B,70-79为C,否则为D):

#include <stdio.h>

int main()
{
    int score = 85;
    if (score >= 90) {
        printf("等级:A\n");
    } else if (score >= 80) { // 隐含条件:score < 90
        printf("等级:B\n"); // 85满足此条件,执行此句
    } else if (score >= 70) { // 隐含条件:score < 80
        printf("等级:C\n");
    } else {
        printf("等级:D\n");
    }
    return 0;
}

运行结果:等级:B

(4)if语句的"坑":悬空else问题

在嵌套if语句时,容易出现 "悬空else" 问题 ——else会默认与最近的未匹配 if结合,而非我们主观认为的外层 if。

反例(错误示范):

#include <stdio.h>

int main() {
    int a = 1, b = 2;
    if (a == 0) // 外层if,条件为假
        if (b == 2) // 内层if,条件为真
            printf("b=2\n");
        else // 悬空else:实际与内层if结合,而非外层if
            printf("a≠0\n");
    return 0;
}

预期:a≠0 → 实际运行结果:无输出(因为内层if条件为真,执行printf后,else不执行)

解决方法:既然默认最近的if与else匹配,若想打破这种局面,只能"强扭这个瓜了",把不想与else匹配的if给括起来,即始终使用大括号{}明确代码块范围,避免歧义:

#include <stdio.h>

int main() {
    int a = 1, b = 2;
    if (a == 0)
    { // 外层if用大括号明确范围
        if (b == 2)
        {
            printf("b=2\n");
        }
    } else { // 此时else明确与外层if结合
        printf("a≠0\n"); // 执行此句
    }
    return 0;
}

运行结果:a≠0

1.2 switch语句:多值匹配的"快捷方式"

当需要根据一个变量的 "多个固定值" 进行判断时(比如根据月份判断季节、根据菜单选项执行操作),switch语句比if-else if更简洁、易读。

(1)基本语法

switch (表达式) { // 表达式结果必须是整数类型(int、char等)
    case 常量1:
        // 表达式值 == 常量1时执行的代码
        break; // 跳出switch语句(关键!)
    case 常量2:
        // 表达式值 == 常量2时执行的代码
        break;
    // ... 更多case
    default:
        // 表达式值与所有case常量不匹配时执行的代码(可选)
        break;
}

核心规则:

  • switch后的 "表达式" 必须是整数类型(不能是 float、double 等);
  • case后的 "常量" 必须是字面量(如 1、'A')或宏定义,不能是变量;
  • break语句的作用是 "执行完当前 case 后,跳出 switch",如果省略,会发生 "case 穿透"(继续执行下一个 case 的代码);
  • default可放在任意位置(通常放最后),当所有 case 都不匹配时执行,没有匹配项且无 default 时,switch 不执行任何代码。

(2)实例:根据月份判断季节

#include <stdio.h>

int main() {
    int month = 3;
    switch (month) {
        case 3:
        case 4:
        case 5: // 3、4、5月均为春季(利用case穿透)
            printf("春季\n");
            break; // 跳出switch
        case 6:
        case 7:
        case 8:
            printf("夏季\n");
            break;
        case 9:
        case 10:
        case 11:
            printf("秋季\n");
            break;
        case 12:
        case 1:
        case 2:
            printf("冬季\n");
            break;
        default:
            printf("无效月份\n");
            break;
    }
    return 0;
}

运行结果:春季

(3)switch vs if-else if:该怎么选?

  • 用switch:当判断条件是 "变量等于多个固定整数" 时(如菜单选项、月份、等级),代码更简洁;
  • 用if-else if:当判断条件是 "范围"(如 score >= 90)或 "复杂逻辑"(如 a > b && c != 0)时,更灵活。

二、循环语句:让程序学会"重复做"

循环语句的核心作用是 "让一段代码重复执行,直到满足终止条件",比如计算 1 到 100 的和、打印 10 次 "Hello World"。C语言中常用的循环语句有三种:while、for、do-while。

2.1 while循环:先判断,再执行

while循环是最基础的循环结构,逻辑是 "先判断条件,条件为真则执行循环体,否则终止循环"。

(1)基本语法

while (条件表达式) {
    // 循环体:条件为真时重复执行的代码
    // (通常需要有"更新条件"的语句,避免死循环)
}

关键注意:循环体中必须有 "更新条件" 的语句(如i++、num -= 2),否则条件永远为真,会导致 "死循环"(程序一直执行循环体,无法退出)。

(2)实例1:打印1到5的数字

#include <stdio.h>

int main()
{
    int i = 1; // 初始化循环变量
    while (i <= 5) // 条件:i不大于5
    {
        printf("%d ", i); // 循环体:打印i
        i++; // 更新条件:i自增1(避免死循环)
    }
    return 0;
}

运行结果:1 2 3 4 5

(3)实例2:计算1到100的和

#include <stdio.h>

int main()
{
    int sum = 0; // 存储总和,初始化为0
    int i = 1; // 循环变量,从1开始
    while (i <= 100) 
    {
        sum += i; // 等价于sum = sum + i
        i++; // i自增,向100靠近
    }
    printf("1到100的和:%d\n", sum);
    return 0;
}

运行结果:1到100的和:5050

(4)实例3:打印100到200的素数

#include <stdio.h>
int main()
{
    int i = 100; // 初始化循环变量(从100开始)
    int b = 2;
    int c = 0;
    int d = 0;
    // 外层while循环:控制100~200的数字
    while (i <= 200)
    {
        c = 0;
        d = i - 1;
        b = 2; // 内层循环变量重置
        // 内层while循环:判断当前i是否为素数
        while (b < d)
        {
            if (i % b == 0)
            {
                c = 1;
                break;
            }
            b++; // 内层循环变量更新
        }
        if (c == 0)
            printf("%d ", i);
        i++; // 外层循环变量更新
    }
    return 0;
}

运行结果:101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199

2.2 for循环:更优雅的"计数循环"

for循环是C语言中最常用的循环结构,尤其适合 "已知循环次数" 的场景(如从 1 循环到 100)。它将 "初始化循环变量""判断条件""更新条件" 三个步骤整合在一行,结构更紧凑。

(1)基本语法

for (初始化表达式; 条件表达式; 更新表达式) {
    // 循环体:条件为真时执行的代码
}

执行流程:

  1. 执行 "初始化表达式"(仅执行 1 次,用于初始化循环变量);
  2. 判断 "条件表达式":
  • 若为真:执行循环体 → 执行 "更新表达式" → 回到步骤 2;
  • 若为假:终止循环,执行 for 循环后的代码。

(2)实例1:用for循环打印1到5

#include <stdio.h>

int main() {
    // 初始化i=1;条件i<=5;更新i++
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    return 0;
}

运行结果:1 2 3 4 5

(3)实例2:用for循环计算1到100的偶数和

#include <stdio.h>

int main() {
    int sum_even = 0;
    // 初始化i=2(第一个偶数);条件i<=100;更新i+=2(每次加2,保持偶数)
    for (int i = 2; i <= 100; i += 2) {
        sum_even += i;
    }
    printf("1到100的偶数和:%d\n", sum_even);
    return 0;
}

运行结果:1到100的偶数和:2550

2.3 do-while循环:先执行,再判断

do-while循环的逻辑是 "先执行一次循环体,再判断条件"—— 这意味着循环体至少会执行一次,适合 "需要先做一次,再判断是否继续" 的场景(如密码验证、菜单交互)。

(1)基本语法

do {
    // 循环体:至少执行一次
    // (同样需要更新条件,避免死循环)
} while (条件表达式); // 注意:末尾有分号

(2)实例:密码验证(至少输入一次密码,直到输入正确)

#include <stdio.h>
#include <string.h> // 用于strcmp函数(比较字符串)

int main() {
    char password[20]; // 存储用户输入的密码
    do {
        printf("请输入密码:");
        scanf("%s", password); // 输入密码(假设正确密码是"123456")
        // strcmp:比较两个字符串,相等返回0,不相等返回非0
    } 
    while (strcmp(password, "123456") != 0); // 密码不正确则继续循环
    printf("密码正确,欢迎进入!\n");
    return 0;
}

运行示例: 请输入密码:abc123 → 请输入密码:123456 → 密码正确,欢迎进入!

(3)用for循环打印100到200的素数

#include <stdio.h>

int main()
{
    int i = 0;
    int b = 2;
    int c = 0; // 作为判断是否为素数的标记
    int d = 0;

    for (i = 100; i <= 200; i++)
    {
        c = 0;
        d = i - 1;
        for(b = 2; b < d; b++)
        {
            if (i % b == 0)
            {
                c = 1;
                break;
            }
        }
        if (c == 0)
            printf("%d ", i);
    }
    return 0;
}

2.4 循环控制:break和continue

在循环中,我们有时需要 "提前终止循环" 或 "跳过当前轮次,直接进入下一轮",这就需要break和continue语句。

(1)break:彻底终止循环

break的作用是 "立即跳出当前所在的循环(while/for/do-while)或 switch 语句",后续循环不再执行。

实例:找到1到10中第一个能被3整除的数:

#include <stdio.h>

int main()
{
    for (int i = 1; i <= 10; i++)
    {
        if (i % 3 == 0) // 若i能被3整除
        {
            printf("找到第一个能被3整除的数:%d\n", i);
            break; // 终止for循环,后续i=4~10不再执行
        }
    }
    return 0;
}

运行结果:找到第一个能被3整除的数:3

(2)continue:跳过当前轮次,进入下一轮

continue的作用是 "跳过当前轮次的循环体剩余代码,直接进入下一轮循环的条件判断"(不会终止循环)。

实例:打印1到10中的奇数(跳过偶数):

#include <stdio.h>

int main() {
    // 打印1到10中的奇数(用continue跳过偶数)
    for (int i = 1; i <= 10; i++) {
        // 如果是偶数,跳过本轮后续代码,直接进入下一轮
        if (i % 2 == 0) {
            continue;  // 关键:跳过本轮的printf,直接执行i++进入下一轮
        }
        // 只有奇数才会执行下面的打印
        printf("奇数:%d\n", i);
    }
    return 0;
}

运行结果: 奇数:1 奇数:3 奇数:5 奇数:7 奇数:9

(3)for循环中的break和continue

for循环中的break(终止整个循环):

#include <stdio.h>
int main() {
    for (int i = 1; i <= 5; i++) {
        if (i == 3) {
            break;  // 当i=3时,终止整个for循环
        }
        printf("i = %d\n", i);
    }
    printf("循环结束\n");
    return 0;
}

运行结果: i = 1 i = 2 循环结束

解析:当i=3时,break触发,直接终止整个for循环,后续的i=4、5不再执行。

for循环中的continue(跳过当前轮次,进入下一轮):

#include <stdio.h>
int main() {
    for (int i = 1; i <= 5; i++) {
        if (i == 3) {
            continue;  // 当i=3时,跳过本轮剩余代码
        }
        printf("i = %d\n", i);
    }
    printf("循环结束\n");
    return 0;
}

运行结果: i = 1 i = 2 i = 4 i = 5 循环结束

解析:当i=3时,continue触发,跳过当前轮次的printf,直接执行i++进入下一轮(i=4)。

(4)while循环中的break和continue

while循环中的break(终止整个循环):

#include <stdio.h>
int main() {
    int i = 1;
    while (i <= 5) {
        if (i == 3) {
            break;  // 当i=3时,终止整个while循环
        }
        printf("i = %d\n", i);
        i++;
    }
    printf("循环结束\n");
    return 0;
}

运行结果: i = 1 i = 2 循环结束

解析:当i=3时,break触发,直接终止while循环,i不再递增。

while循环中的continue(跳过当前轮次,进入下一轮):

#include <stdio.h>
int main() {
    int i = 1;
    while (i <= 5) {
        if (i == 3) {
            i++;  // 注意:while中使用continue前需手动更新循环变量
            continue;  // 跳过本轮剩余代码
        }
        printf("i = %d\n", i);
        i++;
    }
    printf("循环结束\n");
    return 0;
}

运行结果: i = 1 i = 2 i = 4 i = 5 循环结束

(5)注意事项

#include <stdio.h>

int main() 
{
    int i = 1;
    while(i <= 10)
    {
        if(5 == i)
            break;  // break使用不当的点
        printf("%d",i);
        i ++;
    }
    return 0;
}

break使用不当的错误分析:假设开发者的原本意图是「跳过数字5,继续输出后面的数字」,但错误地使用了break:

  • break的作用是立即终止整个循环,而不是跳过当前迭代
  • 当i=5时,执行break会直接退出while循环,导致后面的6~10完全无法输出
  • 最终结果只输出1234,与「跳过5继续输出」的预期完全不符

正确做法:如果需要跳过当前迭代(保留后续循环),应使用continue而非break,同时注意更新循环变量:

#include <stdio.h>

int main()
{
    int i = 1;
    while(i <= 10)
    {
        if(5 == i)
        {
            i++;  // 必须手动更新i,否则会陷入死循环
            continue;  // 仅跳过当前迭代,继续下一次循环
        }
        printf("%d",i);
        i ++;
    }
    return 0;
}

所以要灵活使用break和continue。

2.5 goto语句

在C语言中,goto语句用于无条件跳转到函数内的指定标签位置,其语法格式如下:

goto 标签名;
...
标签名: 语句;  // 标签名后必须跟冒号,且标签需在函数内有效

(1)基本用法示例

#include <stdio.h>

int main() {
    int i = 1;
    
    loop_start:  // 定义标签
    if (i > 5) {
        goto loop_end;  // 跳转到结束标签
    }
    
    printf("%d ", i);
    i++;
    goto loop_start;  // 跳转到开始标签,形成循环
    
    loop_end:  // 结束标签
    printf("\n循环结束");
    return 0;
}

输出结果:1 2 3 4 5 循环结束

(2)特点与争议

优点:

  • 可简化多层循环的退出逻辑(避免嵌套break的繁琐)
  • 在出错处理时,可快速跳转到统一的资源释放位置

缺点:

  • 过度使用会导致代码流程混乱(俗称「面条代码」),降低可读性和可维护性
  • 可能破坏结构化程序设计的逻辑,增加调试难度

典型合理用法:多层循环退出:

#include <stdio.h>

int main() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (i == 1 && j == 1) {
                goto exit_loop;  // 直接退出所有循环
            }
            printf("(%d,%d) ", i, j);
        }
    }
    
exit_loop:  // 退出标签
    printf("\n已退出循环");
    return 0;
}

输出结果:(0,0) (0,1) (0,2) (1,0) 已退出循环

(3)使用建议

  • 尽量避免使用goto,优先通过函数封装、循环条件控制等结构化方式实现逻辑
  • 若必须使用,应遵循:
  • 只在同一函数内跳转
  • 标签名需清晰表达跳转意图(如error_handler、exit_loop)
  • 避免向前跳转(可能导致变量初始化等逻辑被跳过)

三、实战项目:猜数字小游戏

最后,向大家分享一下运用本节知识以及随机数做的猜数字小游戏:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int change()
{
    int N = 0;
    int M = 0;
    while (M == 0) {
        printf("        * *       * *        \n");
        printf("      * * * *   * * * *      \n");
        printf("    * 1:10次 * *  2:8次 *    \n");
        printf("    * 3:5次  * *  4:3次 *    \n");
        printf("      * * * * * * * * *      \n");
        printf("        * HAPPY TIME *        \n");
        printf("          * * * * *          \n");
        printf("            * * *            \n");
        printf("              *              \n");
        scanf("%d", &N);
        if (N == 1) {
            M = 1;
            return 10; 
        }
        else if (N == 2) {
            M = 1;  
            return 8;
        }
        else if (N == 3) {
            return 5;
        }
        else if (N == 4) {
            M = 1;
            return 3;
        }
        else {
            printf("数字无效,请重新输入\n");
        }
    }
    return 0;  
}

void game()
{
    int r = rand() % 100 + 1;
    int guess = 0;
    printf("请选择你要猜的次数\n");
    int left_times = change(); 
    while (left_times > 0)
    {
        printf("您还有%d次机会,加油!\n", left_times);  
        printf("请输入你猜的数字\n");
        scanf("%d", &guess);
        if (guess > r)
        {
            printf("你猜大了\n");
        }
        else if (guess < r)
        {
            printf("你猜小了\n");
        }
        else
        { 
            printf("你猜对了,太棒了!\n");
            break;
        }
        
        left_times--;  // 正确:剩余次数减1
    }
    if (left_times == 0)
    {
        printf("你失败了,正确值是:%d\n", r);
    }
}

void menu()
{
    printf("        * *       * *        \n");
    printf("      * * * *   * * * *      \n");
    printf("    * * * * * * * * * * *    \n");
    printf("    *  play:1   break:0 *    \n");
    printf("      * * * * * * * * *      \n");
    printf("        * * * * * * *        \n");
    printf("          * * * * *          \n");
    printf("            * * *            \n");
    printf("              *              \n");
}

int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("Welcome,请输入0或者1\n");
        scanf("%d", &input);
        switch (input)
        {
        case 0:
            printf("游戏结束\n");
            break;
        case 1:
            game();
            break;
        default:
            printf("请输入正确的数字(0或1)\n");
        }
    } while (input != 0);
    return 0;
}

四、总结

本篇我们学习了C语言分支与循环的核心知识:

  1. 分支语句:
  • if语句:单分支、双分支、多分支,灵活的条件判断
  • switch语句:多值匹配的快捷方式,注意case穿透
  1. 循环语句:
  • while循环:先判断后执行
  • do-while循环:先执行后判断,至少执行一次
  • for循环:最常用的循环结构
  1. 跳转语句:
  • break:终止整个循环
  • continue:跳过当前轮次
  • goto:无条件跳转(谨慎使用)

掌握这些语句的使用方法,将使你的C语言程序更加灵活、高效。在实际编程中,要根据具体场景选择合适的语句,同时注意代码的可读性和可维护性。