C语言分支与循环深度解析

一、开篇介绍

在 C 语言编程里,分支和循环是控制程序流程的核心逻辑,就像交通信号灯指挥车流一样,决定代码执行走向。这篇博客会结合课程资料,把分支、循环的知识点掰开揉碎,从基础语法到实际应用,带着大家吃透这些关键内容,不管是刚入门的新手,还是想巩固基础的同学,都能找到有用的知识 。

二、分支结构(if、switch)

(一)if 语句

  1. 基础语法
    • 单分支:if(条件表达式),条件为真(非 0)就执行大括号里的代码,比如 if(score > 60) { printf("及格啦"); } ,判断分数是否大于 60 来决定是否输出"及格啦"。
    • 双分支:if(条件表达式) { 条件为真执行的代码 } else { 条件为假执行的代码 } ,像判断数字奇偶 if(num % 2 == 0) { printf("偶数"); } else { printf("奇数"); }
    • 多分支:if(条件1) { 执行代码1 } else if(条件2) { 执行代码2 } ... else { 执行代码n } ,用于多个条件判断,比如根据成绩区间输出评级:
c 复制代码
if(score >= 90) { printf("优秀"); } 
else if(score >= 80) { printf("良好"); } 
else if(score >= 60) { printf("及格"); } 
else { printf("不及格"); }
  1. 易错点------悬空 else
    • 规则:else 总是和离它最近且未匹配的 if 配对。看例子:
c 复制代码
if(a > 10)
    if(b < 5)
        printf("A");
else 
    printf("B");
  • 这里 else 会和内部的 if(b < 5) 配对,要是逻辑上想让 else 和外层 if(a > 10) 配对,就得用大括号明确范围:
c 复制代码
if(a > 10) {
    if(b < 5)
        printf("A");
} else {
    printf("B"); 
}

(二)switch 语句

  1. 语法格式
    • 基本结构:
c 复制代码
switch(表达式) {
    case 常量值1: 
        执行语句1; 
        // break; 
    case 常量值2: 
        执行语句2; 
        // break; 
    ...
    default: 
        执行语句n; 
        // break; 
}
  • 表达式结果得是整数类型 (char 也可,因为字符本质是 ASCII 码,属于整数),case 后必须跟常量/常量表达式 (像 12 + 3 ,不能是变量)。
  1. 执行流程与 break 作用
    • 流程:先计算 switch 里表达式的值,然后找匹配的 case ,找到后从该 case 开始依次执行代码,直到遇到 break 或者执行完 switch 里所有语句。
    • break 作用:跳出当前 switch 结构,避免"贯穿"问题。比如:
c 复制代码
int num = 2;
switch(num) {
    case 1:
        printf("一"); 
        // 没有 break,会继续执行下面 case 2 的代码
    case 2:
        printf("二"); 
        break; 
    case 3:
        printf("三"); 
}
// 输出结果是"二",因为 case 1 没 break,但这里 num 匹配 case 2,执行后遇到 break 跳出
  • 如果 num = 1 ,没 break 会输出"一二",这就是贯穿,实际开发一般要靠 break 控制流程。
  1. case 和 default 顺序
    • 规则:casedefault 没有强制顺序要求,不过通常把 default 放最后,作为"兜底"逻辑。比如:
c 复制代码
switch(grade) {
    default:
        printf("未知等级"); 
        break; 
    case 'A':
        printf("优秀"); 
        break; 
    case 'B':
        printf("良好"); 
        break; 
}
  • 这样写语法没问题,但从可读性和逻辑习惯看,建议 default 放末尾,让正常 case 先匹配,特殊情况最后处理。

三、循环结构(while、do-while、for)

(一)while 循环

  1. 语法与执行流程
    • 语法:while(条件表达式) { 循环体语句 } ,先判断条件表达式,为真(非 0)就执行循环体,执行完再回到条件判断,直到条件为假跳出循环。
    • 流程图(结合课程图简化理解):
      值非0 值为0 判断条件表达式 执行循环体语句 结束循环
    • 比如用 while 实现打印 1 到 10:
c 复制代码
int i = 1;
while(i <= 10) {
    printf("%d ", i); 
    i++; 
}
  1. break 和 continue 作用
    • break:直接跳出当前 while 循环,后面循环体不再执行,程序继续往下走。比如:
c 复制代码
int i = 1;
while(i <= 10) {
    if(i == 5) {
        break; 
    }
    printf("%d ", i); 
    i++; 
}
// 输出 1 2 3 4,i 到 5 时 break,循环终止
  • continue:跳过当前循环体剩余语句,直接回到条件判断。例如:
c 复制代码
int i = 0;
while(i < 10) {
    i++; 
    if(i == 5) {
        continue; 
    }
    printf("%d ", i); 
}
// 输出 1 2 3 4 6 7 8 9 10,i=5 时跳过 printf,继续下一轮循环

(二)do-while 循环

  1. 语法与执行流程
    • 语法:
c 复制代码
do {
    循环体语句 
} while(条件表达式); 
  • 执行流程:先执行一次循环体,再判断条件表达式,为真继续循环,为假跳出。和 while 最大区别是至少执行一次循环体
  • 流程图(简化):
    值非0 值为0 执行循环体语句 判断条件表达式 结束循环
  • 示例:输入密码,至少让用户输一次,用 do-while 实现:
c 复制代码
char password[20];
do {
    printf("请输入密码:"); 
    scanf("%s", password); 
} while(strcmp(password, "123456") != 0); 
printf("密码正确,进入系统!"); 
  1. 和 while 循环对比
    • 应用场景:不确定循环次数,但至少要执行一次循环体时,选 do-while (像上面输密码场景);循环可能一次都不执行(比如条件一开始就不满足),用 while 更合适。
    • 执行顺序:while 先判断后执行,do-while 先执行后判断,这是核心差异。

(三)for 循环

  1. 语法与执行流程
    • 语法:for(初始化表达式; 条件表达式; 更新表达式) { 循环体语句 }
      • 初始化表达式:循环前初始化变量(一般用于定义循环控制变量,如 int i = 0 )。
      • 条件表达式:决定是否继续循环,为真执行循环体。
      • 更新表达式:每次循环体执行完后更新变量(常用来改变循环控制变量,如 i++ )。
    • 执行流程(简化步骤):
      ① 执行初始化表达式(只执行一次)→ ② 判断条件表达式,为真执行循环体 → ③ 执行完循环体,执行更新表达式 → 回到② 重复,直到条件为假。
    • 示例:打印 1 到 10,用 for 循环:
c 复制代码
for(int i = 1; i <= 10; i++) {
    printf("%d ", i); 
}
  1. break 和 continue 作用
    • while 循环里的作用逻辑一样:
    • break:跳出 for 循环,比如:
c 复制代码
for(int i = 1; i <= 10; i++) {
    if(i == 5) {
        break; 
    }
    printf("%d ", i); 
}
// 输出 1 2 3 4
  • continue:跳过当前循环体剩余内容,回到更新表达式,再判断条件。例如:
c 复制代码
for(int i = 1; i <= 10; i++) {
    if(i == 5) {
        continue; 
    }
    printf("%d ", i); 
}
// 输出 1 2 3 4 6 7 8 9 10
  1. 与 while 循环对比
    • 语法紧凑性:for 把初始化、条件判断、更新写在一起,适合明确知道循环变量变化的场景,代码更集中;while 更灵活,初始化和更新可分散在代码不同位置。
    • 使用场景:循环次数固定或易通过变量控制时,优先用 for (如遍历数组);循环条件复杂,和循环变量关联弱,用 while

四、循环与分支的综合应用(以猜数字游戏为例)

(一)游戏逻辑拆解

  1. 需求:程序生成 1 - 100 随机数,玩家输入数字猜测,程序提示"大了""小了",直到猜中,还能选择继续玩或退出。
  2. 涉及知识点:
    • 随机数生成:用 rand() 函数(需搭配 srand((unsigned int)time(NULL)) 设置随机种子,避免每次随机数一样),生成 1 - 100 随机数写法 rand() % 100 + 1
    • 循环:用 while 实现猜数过程循环,直到猜中;用 do-while 实现游戏菜单选择(至少显示一次菜单)。
    • 分支:switch 处理菜单选择(玩游戏、退出),if-else 处理猜数结果反馈(大了、小了、猜中)。

(二)参考代码与解析

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 游戏逻辑函数
void game() {
    int ret = rand() % 100 + 1; // 生成 1 - 100 随机数
    int guess = 0;
    while(1) {
        printf("请输入猜测的数字:"); 
        scanf("%d", &guess); 
        if(guess < ret) {
            printf("猜小了\n"); 
        } else if(guess > ret) {
            printf("猜大了\n"); 
        } else {
            printf("恭喜你,猜对了,数字是:%d\n", ret); 
            break; // 猜中跳出循环
        }
    }
}

// 菜单函数
void menu() {
    printf("********************\n");
    printf("*****  1. play  *****\n");
    printf("*****  0. exit  *****\n");
    printf("********************\n");
}

int main() {
    int input = 0;
    srand((unsigned int)time(NULL)); // 设置随机种子
    do {
        menu(); 
        printf("请选择:"); 
        scanf("%d", &input); 
        switch(input) {
            case 1:
                game(); 
                break; 
            case 0:
                printf("退出游戏\n"); 
                break; 
            default:
                printf("选择错误,重新选择\n"); 
                break; 
        }
    } while(input != 0); // 输入 0 退出循环
    return 0; 
}

(三)代码关键解析

  1. 随机数部分:
    • srand((unsigned int)time(NULL)) :利用当前系统时间作为随机种子,让每次程序运行生成的随机数不同,要放在 main 函数开头,且只需要调用一次。
    • rand() % 100 + 1rand() 生成 0 - RAND_MAX(一般是 32767)的数,取模 100 得到 0 - 99,加 1 变成 1 - 100 范围。
  2. 循环部分:
    • 外层 do-while :保证菜单至少显示一次,根据输入决定进入游戏、退出还是重新选择。
    • 内层 while(1) :实现猜数循环,直到猜中用 break 跳出。
  3. 分支部分:
    • switch 处理菜单输入,清晰区分不同选择逻辑。
    • if-elsegame 函数里处理猜数结果,给玩家反馈。

五、逻辑运算符与短路求值

(一)逻辑运算符介绍(结合课程表格)

运算符 名称 规则(a、b 为表达式,非 0 为真,0 为假) 示例
! 逻辑非 !a ,a 为真则结果为假(0),a 为假则结果为真(1) !5 结果是 0!0 结果是 1
&& 逻辑与 a && b ,a 和 b 都为真,结果才为真(1),否则为假(0) 3 && 5 结果 10 && 5 结果 0

| || | 逻辑或 | a || b ,a 或 b 有一个为真,结果就为真(1),都假才假(0) | 0 || 5 结果 10 || 0 结果 0 |

(二)短路求值特性

  1. 逻辑与(&& )短路:
    • 当左边表达式为假(0)时,右边表达式不会执行 ,因为整个 && 表达式结果已经确定为假。比如:
c 复制代码
int a = 0, b = 5;
if(a && (b++)) { 
    // 左边 a 为 0,右边 b++ 不会执行,b 还是 5 
}
printf("b = %d", b); // 输出 b = 5
  1. 逻辑或(|| )短路:
    • 当左边表达式为真(非 0)时,右边表达式不会执行 ,因为整个 || 表达式结果已经确定为真。例如:
c 复制代码
int a = 5, b = 0;
if(a || (b++)) { 
    // 左边 a 为真,右边 b++ 不会执行,b 还是 0 
}
printf("b = %d", b); // 输出 b = 0
  1. 应用与注意事项:
    • 合理利用短路可优化代码(比如判断指针不为空再访问其内容 if(p != NULL && *p > 10) ,避免空指针访问崩溃)。
    • 但要注意,依赖短路的逻辑如果修改表达式顺序,可能改变程序行为,写代码时要清晰考虑执行顺序。

六、常见易错点总结

  1. 循环条件写错:比如把 while(i < 10) 写成 while(i > 10) ,导致循环不执行或死循环;for 循环里更新表达式写错(如 i-- 写成 i++ ),改变循环走向。
  2. 分支匹配混乱:if-else 嵌套时没正确用大括号,出现悬空 else 问题;switch 里忘记加 break ,造成逻辑贯穿。
  3. 随机数使用不当:没设置随机种子 srand ,或者 rand 生成范围计算错误,导致随机数不符合预期。
  4. 短路求值忽略:在依赖多个表达式都执行的场景用了逻辑与/或,因短路导致部分代码没执行,引发逻辑错误(比如想同时判断 a++b++ ,用 if(a++ && b++) ,若 a++ 为假,b++ 不执行,b 值没按预期改变)。

七、总结

分支(if、switch)与循环(while、do-while、for)是 C 语言流程控制的核心。理解语法、执行流程,规避易错点,结合逻辑运算符、短路求值优化代码,再通过实战(如猜数字游戏)反复打磨,就能让程序精准按预期执行。

相关推荐
悦悦子a啊16 分钟前
Python之--集合
开发语言·python·编程
程序员编程指南18 分钟前
Qt字符串处理与正则表达式应用
c语言·c++·qt·正则表达式
运维帮手大橙子25 分钟前
字符串缓冲区和正则表达式
java·开发语言
慢慢沉2 小时前
Lua(数据库访问)
开发语言·数据库·lua
GISer_Jing2 小时前
50道JavaScript基础面试题:从基础到进阶
开发语言·javascript·ecmascript
Python涛哥2 小时前
PHP框架之Laravel框架教程:1. laravel搭建
开发语言·php·laravel
一百天成为python专家2 小时前
数据可视化
开发语言·人工智能·python·机器学习·信息可视化·numpy
武子康6 小时前
Java-82 深入浅出 MySQL 内部架构:服务层、存储引擎与文件系统全覆盖
java·开发语言·数据库·学习·mysql·spring·微服务
惜.己6 小时前
pytest中使用skip跳过某个函数
开发语言·python·测试工具·pytest
姜暮儿6 小时前
C++ 性能优化
开发语言·c++