青江的个人站

“保持热爱,奔赴星海”

  • 主页
  • 目录
  • 图床
  • 留言板
  • -关于我-
友链 搜索文章 >>

青江的个人站

“保持热爱,奔赴星海”

  • 主页
  • 目录
  • 图床
  • 留言板
  • -关于我-

【C语言学习笔记】四、分支与跳转


阅读数: 0次    2025-06-29
字数:3.6k字 | 预计阅读时长:14分钟

1. 决策控制

编程语言最初的设计,是为了:

  1. 反映现实世界的复杂性;
  2. 灵活性,可以根据不同的情况做出不同的响应。

要搞清楚程序背后的逻辑。

2. if和if else

基础的语法为:

1
2
3
if (expression) {
statement1;
}

expression是一个结果为真(true)或假(false)的表达式,当它为真的时候,执行括号里的statement,当它是假的时候直接跳出括号,继续执行下面的程序。

语法也可以为:

1
2
3
4
5
6
if (expression) {
statement1;
}
else {
statement2;
}

这时候,expression也是一个结果为真(true)或假(false)的表达式,当它为真的时候,执行if括号里的statement1,当它是假的时候,执行else括号里的statement2。

例如:

1
2
3
4
5
6
7
8
uint32_t number = 100;

if (number > 10) {
printf("这个数大于10!\n"); // 执行
}
else {
printf("这个数小于等于10!\n"); // 不执行
}

这个例子中,if条件中的表达式判定为真,因此执行其括号中的语句,else中过的语句直接跳过,不执行。

当然,当条件中的statement只有一行语句时,大括号可以省略,此时else与离它最近的一个if相匹配,但是在实际使用过程中,不管语句有几条,都应该加上大括号,提高代码的可读性。

3. else if

可以在if和else语句中间加一个或多个else if语句,每一个语句对应一个表达式(expression),此时程序会从上到下一层一层判断每一个expression是否为真,如果某一个表达式的结果为真,则程序执行其大括号中的所有语句,然后跳出这个if&else逻辑,如果所有的表达式都为假,则程序执行else语句中的所有语句。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t number = 10;

if (number > 10) {
printf("这个数大于10!\n"); // 不执行
}
else if (number <= 5) {
printf("这个数小于等于5!\n"); // 不执行
}
else if (number == 10) {
printf("这个数等于10!\n"); // 执行
}
else {
printf("这个数大于5且小于10!\n"); // 不执行
}

程序从上到下,一层一层判断,发现第三个条件为真,则执行其中的语句。

如果所有条件都不满足,则执行else中的语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t number = 6;

if (number > 10) {
printf("这个数大于10!\n"); // 不执行
}
else if (number <= 5) {
printf("这个数小于等于5!\n"); // 不执行
}
else if (number == 10) {
printf("这个数等于10!\n"); // 不执行
}
else {
printf("这个数大于5且小于10!\n"); // 执行
}

4. if嵌套

if语句可以嵌套使用,也就是在满足某一种条件下再进行判断,是否满足其他条件,并执行对应的语句,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
uint32_t number = 5;

if (number > 10) {
printf("这个数大于10!\n"); // 不执行
}
else if (number <= 5) {
printf("这个数小于等于5!\n"); // 执行
if (number <= 3) {
printf("这个数小于等于3!\n"); // 不执行
}
else if (number == 5) {
printf("这个数等于5!\n"); // 执行
}
else {
printf("这个数是4!\n"); // 不执行
}
}
else if (number == 10) {
printf("这个数等于10!\n"); // 不执行
}
else {
printf("这个数大于5且小于10!\n"); // 不执行
}

判断第二个条件满足后,程序进行下一组if语句的判断。

5. 为何要避免嵌套&入门提醒

企业中if的嵌套不常用,过多的嵌套层次会使得代码难以阅读和维护,如果可以的话,尽量使用一层if-else来解决问题。

同样的,一个if中的条件表达式太过复杂,例如包含多个与、或等逻辑,也会使理解和维护代码变得困难。

企业中,如果需要避免用到多层嵌套的情况,会使用策略模式(Strategy Pattern)代替,这属于面向对象的知识,不属于C语言的范畴。

对于面向过程的C语言,一般不适合做这种工作,不过使用结构体,定义策略接口也可以实现类似的功能。

6. 逻辑与或的短路行为

使用逻辑与、逻辑或作为if中的条件来处理出现较少的情况的行为称之为短路。

例如:事件A和事件B同时满足时,结果输出为true,否则为false:

1
2
3
4
5
6
7
8
9
10
11
12
bool is_event_A = true;
bool is_event_B = false;
bool result;

if (is_event_A && is_event_B) {
result = true;
}
else {
result = false;
}

printf("result = %s\n", result ? "true" : "false"); // 输出:result = false

又例如:事件A和事件B满足其中一个,即输出true,否则为false:

1
2
3
4
5
6
7
8
9
10
11
12
bool is_event_A = true;
bool is_event_B = false;
bool result;

if (is_event_A || is_event_B) {
result = true;
}
else {
result = false;
}

printf("result = %s\n", result ? "true" : "false"); // 输出:result = true

多写!多练习!

7. 访问权限的简单应用案例

下面是一个访问权限的简单案例,展示几种不同的写法。

程序要求当事件A、事件B与事件C满足其中一种情况时,则允许访问,否则拒绝访问。

第一种写法使用if和else if对每种条件进行判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool is_event_A = false;
bool is_event_B = true;
bool is_event_C = false;

if (is_event_A) {
puts("事件A满足,允许访问"); // 不执行
}
else if (is_event_B) {
puts("事件B满足,允许访问"); // 执行
}
else if (is_event_C) {
puts("事件C满足,允许访问"); // 不执行
}
else {
puts("没有事件满足,禁止访问"); // 不执行
}

这种写法的可读性和可扩展性较差,如果还有其他条件时,就需要加入if-else语句的嵌套,进一步降低可读性。

puts()是直接输出,对比格式化输出(printf())更简洁。

第二种写法是在if-else条件判断之前先检查访问条件,这种情况下的注释一定要写完整,提高代码的可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool is_event_A = false;
bool is_event_B = true;
bool is_event_C = false;

// 检查访问条件
// 如果 is_event_A, is_event_B 或 is_event_C 中的任意一个为 true,则允许访问
bool access_allowed = is_event_A || is_event_B || is_event_C;

if (access_allowed) {
puts("允许访问");
}
else {
puts("拒绝访问");
}

这种写法在某些情况下的可读性要好一点,在if-else之前就已经判断了此时的访问条件。

同样的,也可以将所有判断都放在if的条件中:

1
2
3
4
5
6
7
// 如果 is_event_A, is_event_B 或 is_event_C 中的任意一个为 true,则允许访问
if (is_event_A || is_event_B || is_event_C) {
puts("允许访问");
}
else {
puts("拒绝访问");
}

这种写法也需要写完备的注释,提高程序的可读性。

8. switch...case的用途

switch...case语句帮助控制复杂条件和分支运算,switch语句将控制权转交给其他主题中的语句。

假设事件A、事件B、事件C分别对应stage参数的1、2、3,每个阶段必须满足对应的事件,才允许访问,否则禁止访问。

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
uint8_t stage = 2;

bool is_event_A = false;
bool is_event_B = true;
bool is_event_C = false;

bool access_allowed = false;

switch (stage) {
case 1:
if (is_event_A) {
access_allowed = true;
}
break;
case 2:
if (is_event_B) {
access_allowed = true;
}
break;
case 3:
if (is_event_C) {
access_allowed = true;
}
break;
default:
access_allowed = false;
break;
}

if (access_allowed) {
puts("允许访问");
}
else {
puts("禁止访问");
}

这种写法类似一个电梯,先从switch中拿到想要去的楼层,对应某一个case语句,再执行这个对应的case语句中的代码。在某些情况下,代码可读性和可扩展性都有所提高。

注意每一个case的最后一定要有break;语句,使得程序在当前的case执行完成之后就跳出switch...case语句,防止继续判断下一个case的情况发生。

default与else类似,当所有条件不符合的时候,则执行当前语句。

企业代码的case中,一般不会直接写if条件判断,都是引出外部函数来简化代码:

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
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

// 检查事件函数声明
bool check_event_A(bool is_event_A);
bool check_event_B(bool is_event_B);
bool check_event_C(bool is_event_C);

int main(void) {

uint8_t stage = 2;

bool is_event_A = false;
bool is_event_B = true;
bool is_event_C = false;

bool access_allowed = false;

switch (stage) {
case 1:
// 检查事件A
access_allowed = check_event_A(is_event_A);
break;
case 2:
// 检查事件B
access_allowed = check_event_B(is_event_B);
break;
case 3:
// 检查事件C
access_allowed = check_event_C(is_event_C);
break;
default:
access_allowed = false;
break;
}

if (access_allowed) {
puts("允许访问");
}
else {
puts("禁止访问");
}

return 0;
}

// 检查事件函数
bool check_event_A(bool is_event_A) {
return is_event_A;
}
bool check_event_B(bool is_event_B) {
return is_event_B;
}
bool check_event_C(bool is_event_C) {
return is_event_C;
}

如果以后需要修改检查事件函数的逻辑,直接找到对应的函数进行修改即可。

9. 再探条件运算符? :

条件运算符也可以嵌套使用,做多层条件的判断,代替多个if-else语句。

例如,实现一个得分评级程序,90分以上是A,80分到90分是B,70分到80分是C,其他情况是D。这种情况下使用if-else语句就会比较啰嗦:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint8_t score = 86;

char grade;

if (score >= 90) {
grade = 'A';
}
else if (score >= 80) {
grade = 'B';
}
else if (score >= 70) {
grade = 'C';
}
else {
grade = 'D';
}

printf("得分:%" PRIu8 ",等级:%c\n", score, grade);

使用条件运算符代替:

1
2
3
4
5
6
7
uint8_t score = 86;

char grade = (score >= 90) ? 'A' :
(score >= 80) ? 'B' :
(score >= 70) ? 'C' : 'D';

printf("得分:%" PRIu8 ",等级:%c\n", score, grade);

这样写就比单纯的if-else语句要简单很多。

写这种条件运算符嵌套的时候尽量分行,提高代码的可读性,当第一个条件不符合的时候,程序跳到第二行,当第二行的条件不符合的时候,跳到第三行。

事实上,上面的条件运算符嵌套与下面的if-else语句逻辑相同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (score >= 90) {
grade = 'A';
}
else {
if (score >= 80)
{
grade = 'B';
}
else {
if (score >= 70) {
grade = 'C';
}
else {
grade = 'D';
}
}
}

但显而易见,使用条件运算符嵌套,比使用if-else嵌套要易读很多。

10. 检查账户锁定案例与提前return出

案例:输入密码,当输入次数大于3的时候,即锁定账户并结束程序,后面的其他代码不被执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(void) {
uint32_t wrong_attempts = 3;
bool is_locked = wrong_attempts >= 3; // 密码如果连续输入错误3次则锁定

if (is_locked) {
puts("账户被锁定!");
return 0; // 提前退出程序
}

puts("继续执行程序..."); // 被锁定时不再执行

return 0;
}

11. 卫语句的使用:租车案例

案例:当年龄大于或等于22岁,驾驶经验在两年以上,才可以租车,否则不给租赁。

用常规的if-else语句可以实现:

1
2
3
4
5
6
7
8
uint8_t age = 25;
uint8_t driving_exp_years = 3;

if (age >= 22 && driving_exp_years >= 2) {
puts("满足条件,可以租车!");
} else {
puts("不满足条件,不能租车!");
}

这种写法判断的是正向的条件,满足所有两个条件,才可以租车。

更好的做法是从反向来判断,运用上一节提到的提前return出,在不满足条件时直接退出程序,不继续执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(void) {
uint8_t age = 25;
uint8_t driving_exp_years = 3;

if (age < 22) {
puts("年龄不满足,不能租车!");
return 0;
}

if (driving_exp_years < 2) {
puts("驾驶经验不足,不能租车!");
return 0;
}

puts("满足条件,可以租车!");

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
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>

void check_car_rent(uint8_t age, uint8_t driving_exp_years);

int main(void) {
check_car_rent(25, 3);

return 0;
}

void check_car_rent(uint8_t age, uint8_t driving_exp_years) {
if (age < 22) {
puts("年龄不满足,不能租车!");
return;
}

if (driving_exp_years < 2) {
puts("驾驶经验不足,不能租车!");
return;
}

puts("满足条件,可以租车!");
}

12. 状态机:switch红绿灯的简单应用

状态机可以使用switch...case来管理复杂状态转换,例如一个红绿灯的简单程序,默认状态是红灯(0),如果是红灯,则切换到绿灯(1),如果是绿灯,则切换为黄灯(2),如果是黄灯,则切换回红灯。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint8_t traffic_light_state = 0;	// 初始状态为红灯

switch (traffic_light_state) {
case 0:
puts("当前是红灯,切换为绿灯");
traffic_light_state = 1; // 切换为绿灯
break;
case 1:
puts("当前是绿灯,切换为黄灯");
traffic_light_state = 2; // 切换为黄灯
break;
case 2:
puts("当前是黄灯,切换为红灯");
traffic_light_state = 0;
break;
default:
break;
}

正常来说应该加上循环,使得状态自动进行切换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
uint8_t traffic_light_state = 0;	// 初始状态为红灯

for (int i = 0; i < 5; i++)
{
switch (traffic_light_state) {
case 0:
puts("当前是红灯,切换为绿灯");
traffic_light_state = 1; // 切换为绿灯
break;
case 1:
puts("当前是绿灯,切换为黄灯");
traffic_light_state = 2; // 切换为黄灯
break;
case 2:
puts("当前是黄灯,切换为红灯");
traffic_light_state = 0;
break;
default:
break;
}
}

且状态切换应该放在函数中进行,各种状态也一般会用枚举来定义。

13. switch-case与if-else的根本区别

if-else语句中传入的是一个结果为真(true)或假(false)的表达式,也就是表达式的结果必须是bool类型;而switch...case语句最典型的例子就是“电梯”,向switch中传入的表达式的值必须是常规的整型,不能是其他的任何类型,因此对应的,每个case的值也需要是整型。

14. 第四章结束语以及警示

卫语句的使用和编程思维很重要!

自己找一些练习题做练习!

多思考多练习案例!

编程是循序渐进的过程:

  1. 理解代码的逻辑;
  2. 自己能理解代码为什么要这样写,可以思考明白代码背后的逻辑;
  3. 足够的训练,动手把代码敲出来。
本文来源: 青江的个人站
本文链接: https://hanqingjiang.com/2025/06/29/20250629_C_branchesAndJumps/
版权声明: 本作品采用 CC BY-NC-SA 4.0 进行许可。转载请注明出处!
知识共享许可协议
赏

谢谢你请我喝可乐~

支付宝
微信
  • Notes
  • C

扫一扫,分享到微信

微信分享二维码
【C语言学习笔记】三、运算符
  1. 1. 1. 决策控制
  2. 2. 2. if和if else
  3. 3. 3. else if
  4. 4. 4. if嵌套
  5. 5. 5. 为何要避免嵌套&入门提醒
  6. 6. 6. 逻辑与或的短路行为
  7. 7. 7. 访问权限的简单应用案例
  8. 8. 8. switch...case的用途
  9. 9. 9. 再探条件运算符? :
  10. 10. 10. 检查账户锁定案例与提前return出
  11. 11. 11. 卫语句的使用:租车案例
  12. 12. 12. 状态机:switch红绿灯的简单应用
  13. 13. 13. switch-case与if-else的根本区别
  14. 14. 14. 第四章结束语以及警示
© 2021-2025 青江的个人站
晋ICP备2024051277号-1
powered by Hexo & Yilia
  • 友链
  • 搜索文章 >>

tag:

  • 生日快乐🎂
  • 新年快乐!
  • 小技巧
  • Linux
  • 命令
  • 语录
  • 复刻
  • Blog
  • Notes
  • Android
  • C
  • FPGA
  • Homework
  • MATLAB
  • Server
  • Vivado

  • 引路人-稚晖
  • Bilibili-稚晖君
  • 超有趣讲师-Frank
  • Bilibili-Frank