一、开篇介绍
在 C 语言编程里,分支和循环是控制程序流程的核心逻辑,就像交通信号灯指挥车流一样,决定代码执行走向。这篇博客会结合课程资料,把分支、循环的知识点掰开揉碎,从基础语法到实际应用,带着大家吃透这些关键内容,不管是刚入门的新手,还是想巩固基础的同学,都能找到有用的知识 。
二、分支结构(if、switch)
(一)if 语句
- 基础语法
- 单分支:
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("不及格"); }
- 易错点------悬空 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 语句
- 语法格式
- 基本结构:
c
switch(表达式) {
case 常量值1:
执行语句1;
// break;
case 常量值2:
执行语句2;
// break;
...
default:
执行语句n;
// break;
}
- 表达式结果得是整数类型 (char 也可,因为字符本质是 ASCII 码,属于整数),case 后必须跟常量/常量表达式 (像
1
、2 + 3
,不能是变量)。
- 执行流程与 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
控制流程。
- case 和 default 顺序
- 规则:
case
和default
没有强制顺序要求,不过通常把default
放最后,作为"兜底"逻辑。比如:
- 规则:
c
switch(grade) {
default:
printf("未知等级");
break;
case 'A':
printf("优秀");
break;
case 'B':
printf("良好");
break;
}
- 这样写语法没问题,但从可读性和逻辑习惯看,建议
default
放末尾,让正常case
先匹配,特殊情况最后处理。
三、循环结构(while、do-while、for)
(一)while 循环
- 语法与执行流程
- 语法:
while(条件表达式) { 循环体语句 }
,先判断条件表达式,为真(非 0)就执行循环体,执行完再回到条件判断,直到条件为假跳出循环。 - 流程图(结合课程图简化理解):
值非0 值为0 判断条件表达式 执行循环体语句 结束循环 - 比如用
while
实现打印 1 到 10:
- 语法:
c
int i = 1;
while(i <= 10) {
printf("%d ", i);
i++;
}
- break 和 continue 作用
- break:直接跳出当前
while
循环,后面循环体不再执行,程序继续往下走。比如:
- break:直接跳出当前
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 循环
- 语法与执行流程
- 语法:
c
do {
循环体语句
} while(条件表达式);
- 执行流程:先执行一次循环体,再判断条件表达式,为真继续循环,为假跳出。和
while
最大区别是至少执行一次循环体。 - 流程图(简化):
值非0 值为0 执行循环体语句 判断条件表达式 结束循环 - 示例:输入密码,至少让用户输一次,用
do-while
实现:
c
char password[20];
do {
printf("请输入密码:");
scanf("%s", password);
} while(strcmp(password, "123456") != 0);
printf("密码正确,进入系统!");
- 和 while 循环对比
- 应用场景:不确定循环次数,但至少要执行一次循环体时,选
do-while
(像上面输密码场景);循环可能一次都不执行(比如条件一开始就不满足),用while
更合适。 - 执行顺序:
while
先判断后执行,do-while
先执行后判断,这是核心差异。
- 应用场景:不确定循环次数,但至少要执行一次循环体时,选
(三)for 循环
- 语法与执行流程
- 语法:
for(初始化表达式; 条件表达式; 更新表达式) { 循环体语句 }
- 初始化表达式:循环前初始化变量(一般用于定义循环控制变量,如
int i = 0
)。 - 条件表达式:决定是否继续循环,为真执行循环体。
- 更新表达式:每次循环体执行完后更新变量(常用来改变循环控制变量,如
i++
)。
- 初始化表达式:循环前初始化变量(一般用于定义循环控制变量,如
- 执行流程(简化步骤):
① 执行初始化表达式(只执行一次)→ ② 判断条件表达式,为真执行循环体 → ③ 执行完循环体,执行更新表达式 → 回到② 重复,直到条件为假。 - 示例:打印 1 到 10,用
for
循环:
- 语法:
c
for(int i = 1; i <= 10; i++) {
printf("%d ", i);
}
- 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
- 与 while 循环对比
- 语法紧凑性:
for
把初始化、条件判断、更新写在一起,适合明确知道循环变量变化的场景,代码更集中;while
更灵活,初始化和更新可分散在代码不同位置。 - 使用场景:循环次数固定或易通过变量控制时,优先用
for
(如遍历数组);循环条件复杂,和循环变量关联弱,用while
。
- 语法紧凑性:
四、循环与分支的综合应用(以猜数字游戏为例)
(一)游戏逻辑拆解
- 需求:程序生成 1 - 100 随机数,玩家输入数字猜测,程序提示"大了""小了",直到猜中,还能选择继续玩或退出。
- 涉及知识点:
- 随机数生成:用
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;
}
(三)代码关键解析
- 随机数部分:
srand((unsigned int)time(NULL))
:利用当前系统时间作为随机种子,让每次程序运行生成的随机数不同,要放在main
函数开头,且只需要调用一次。rand() % 100 + 1
:rand()
生成 0 - RAND_MAX(一般是 32767)的数,取模 100 得到 0 - 99,加 1 变成 1 - 100 范围。
- 循环部分:
- 外层
do-while
:保证菜单至少显示一次,根据输入决定进入游戏、退出还是重新选择。 - 内层
while(1)
:实现猜数循环,直到猜中用break
跳出。
- 外层
- 分支部分:
switch
处理菜单输入,清晰区分不同选择逻辑。if-else
在game
函数里处理猜数结果,给玩家反馈。
五、逻辑运算符与短路求值
(一)逻辑运算符介绍(结合课程表格)
运算符 | 名称 | 规则(a、b 为表达式,非 0 为真,0 为假) | 示例 |
---|---|---|---|
! |
逻辑非 | !a ,a 为真则结果为假(0),a 为假则结果为真(1) |
!5 结果是 0 ;!0 结果是 1 |
&& |
逻辑与 | a && b ,a 和 b 都为真,结果才为真(1),否则为假(0) |
3 && 5 结果 1 ;0 && 5 结果 0 |
| ||
| 逻辑或 | a || b
,a 或 b 有一个为真,结果就为真(1),都假才假(0) | 0 || 5
结果 1
;0 || 0
结果 0
|
(二)短路求值特性
- 逻辑与(
&&
)短路:- 当左边表达式为假(0)时,右边表达式不会执行 ,因为整个
&&
表达式结果已经确定为假。比如:
- 当左边表达式为假(0)时,右边表达式不会执行 ,因为整个
c
int a = 0, b = 5;
if(a && (b++)) {
// 左边 a 为 0,右边 b++ 不会执行,b 还是 5
}
printf("b = %d", b); // 输出 b = 5
- 逻辑或(
||
)短路:- 当左边表达式为真(非 0)时,右边表达式不会执行 ,因为整个
||
表达式结果已经确定为真。例如:
- 当左边表达式为真(非 0)时,右边表达式不会执行 ,因为整个
c
int a = 5, b = 0;
if(a || (b++)) {
// 左边 a 为真,右边 b++ 不会执行,b 还是 0
}
printf("b = %d", b); // 输出 b = 0
- 应用与注意事项:
- 合理利用短路可优化代码(比如判断指针不为空再访问其内容
if(p != NULL && *p > 10)
,避免空指针访问崩溃)。 - 但要注意,依赖短路的逻辑如果修改表达式顺序,可能改变程序行为,写代码时要清晰考虑执行顺序。
- 合理利用短路可优化代码(比如判断指针不为空再访问其内容
六、常见易错点总结
- 循环条件写错:比如把
while(i < 10)
写成while(i > 10)
,导致循环不执行或死循环;for
循环里更新表达式写错(如i--
写成i++
),改变循环走向。 - 分支匹配混乱:
if-else
嵌套时没正确用大括号,出现悬空else
问题;switch
里忘记加break
,造成逻辑贯穿。 - 随机数使用不当:没设置随机种子
srand
,或者rand
生成范围计算错误,导致随机数不符合预期。 - 短路求值忽略:在依赖多个表达式都执行的场景用了逻辑与/或,因短路导致部分代码没执行,引发逻辑错误(比如想同时判断
a++
和b++
,用if(a++ && b++)
,若a++
为假,b++
不执行,b
值没按预期改变)。
七、总结
分支(if、switch)与循环(while、do-while、for)是 C 语言流程控制的核心。理解语法、执行流程,规避易错点,结合逻辑运算符、短路求值优化代码,再通过实战(如猜数字游戏)反复打磨,就能让程序精准按预期执行。