05-控制流(分支结构)
一、二路分支
程序中某一段代码需要满足一定的条件才会被执行。
- if 语句:用于表达一种条件,如果条件满足则执行某个代码块。
- if-else 语句:用于表达一种条件,如果条件满足则执行某个代码块,否则执行另外一个代码块。
// if 语句
int a = 100;
if (a > 100) { // 判断条件
/* 如果满足则执行该代码块 */
printf("耗子尾汁!!\n");
}
// if-else 语句
if (a < 99) {
printf("大意了!!\n");
} else {
printf("没有闪!!!\n");
}
// if-else if-else 语句
if (a < 99) {
printf("大意了!!\n");
} else if (a > 99) {
printf("没有闪!!!\n");
} else {
printf("不讲武德!!!\n");
}
注意:
if
语句可以单独使用,但else
不可以单独使用,必须在if
后面配套使用。- 建议为
if
和else
配对的大括号{ }
。否则,需要注意只能识别if
/else
后面的第一个逻辑行的语句。
if (a > 1)
printf("Hello\n"); // if 的第一个逻辑行
else
printf("Jacy\n"); // else 的第一个逻辑行
printf("Even\n"); // 注意此行代码已经不在 else 的管辖范围内
二、 多路分支
根据不同的条件来执行不同的代码块。
switch (表达式<判断的条件>) {
case <常量1>:
// 代码块 1
break;
case <常量2>:
// 代码块 2
break;
case <常量3>:
// 代码块 3
break;
default:
// 代码块 N
}
2.1 示例
int num = 0;
printf("请你来几拳!!!\n");
scanf("%d", &num);
while(getchar() != '\n'); // 清空标准输入缓冲区
switch (num) {
case 1:
printf("它一个左勾拳!!\n");
break;
case 2:
printf("它一个左勾拳和一个右鞭腿!!\n");
break;
case 3:
printf("一个不小心打我脸上了!!!!!\n");
break;
default:
printf("它怂了!! !!!\n");
}
注意:
switch(num)
语句中的num
必须是一个整型的表达式。case
语句中的常量必须是整型常量,包括普通的字符,不包括被const
修改的整型数据。break
用来中断/跳出当前的循环。如果没有则会从条件满足的语句开始一条一条的往下执行,直到整个switch-case
结束或者遇到其它代码块中的break
。default
并不是必须存在,它一般放在最后面,用来提示用户表示都不满足以上条件。由于在最后面可以不添加break
。
练习:
- 使用if-esle 语句来实现检测用户输入的是大写字符或者是小写字符。(小写字母a到z的ASCII码值从97开,大写是从65开始)
- 使用switch - case 语句来实现用户输入1-7 程序输出星期几
三、const
用来修饰一个变量使之不可被修改。
3.1 作用
- 修饰变量:使得变量不能被修改。
- 修饰指针:使得指针的指向不能改变或者指针所指向的内容不得改变。
int const a = 100; // 定义了一个不可被修改的变量 a
const int b = 200;
a = 300; // 错误 assignment of read-only variable ‘a’
b = 250; // 错误 assignment of read-only variable ‘b’
四、while
和 do...while
循环
使得程序中某一段代码块重复循环执行。
4.1 while
语法
while (表达式) {
// 代码块
}
4.1.2 示例
int num = 10;
while (num) { // 非零则真 (布尔值)
printf("num: %d\n", num--);
}
4.1.3 while
的逻辑
- 先判断条件是否成立,条件为真则执行代码块。
4.2 do...while
do {
// 代码块
} while (表达式);
4.2.1 示例
int num = 10;
do {
printf("num: %d\n", num--);
} while (num);
4.2.2 do...while
的逻辑
- 先执行一次代码块,然后再判断条件是否成立(最少会执行一次代码块)。
注意:
while(num);
是空循环,这个分号要慎重。while
循环先进行判断且条件为真,然后再执行代码块(有可能一次都不执行)。do...while
则是先执行一次代码块,然后再判断条件是否成立(最少会执行一次代码块)。
五、for
循环
与 while
类似,都是让程序中某一段代码块重复运行,但 for
相对 while
来说更加紧凑,把所有的循环控制都集中到一行代码中。
for (初始化语句; 判断语句; 表达式) {
// 代码块
}
5.1示例
for (size_t i = 0; i < num; ++i) {
printf("i: %ld\n", i);
}
for (;;) { // 相当于 while(1) 死循环
printf("死循环\n");
}
注意:
- 初始化语句只会被执行一次。
- 第三个表达式(如
++i
)在第一次循环的时候并没有被执行。 - 第三个表达式中,前缀/后缀(如
++i
和i++
)并不影响i
在循环中取值的先后。 for
循环语句中,三个表达式都可以省略,但是分号必须留下。- 在
for
循环中直接定义并初始化变量只在 C99 及以上的编译规则下可以这样做。
六、break
与 continue
-
break
:跳出循环结构,跳出当前层的循环。 -
continue
:结束当前这一次循环,重新进入下一次的循环。
6.1 示例
for (int i = 0; i < num; ++i) {
while (1) { // 在循环体内部可以嵌套其它的循环
printf("你打我呀!!\n");
break; // 跳出 while 这一层循环,并不影响外面的 for
}
if (i == 5) {
continue; // 跳过当前这一次循环,导致后面的代码在当次循环中不执行
}
printf("i: %d\n", i);
}
while
和do...while
用于重复执行代码块。for
循环将所有的循环控制都集中到一行代码中,使代码更加紧凑。break
用于跳出当前层的循环。continue
用于结束当前这一次循环,直接进入下一次循环。
七、goto语句
goto
语句是一种无条件跳转,可以在程序中跳转到指定的标签位置继续执行。
7.1 语法
int main(int argc, char const *argv[]) {
// 代码块
goto 标签;
标签:
// 代码块
return 0;
}
7.2 实例
以下是一个使用 goto
语句的示例程序:
#include <stdio.h>
int main(int argc, char const *argv[]) {
int num = 0;
printf("请你来几拳!!!\n");
scanf("%d", &num);
while (getchar() != '\n'); // 清空标准输入缓冲区
for (int i = 0; i < num; ++i) {
goto Even; // 无条件跳转到标签为 Even 的位置
}
Even:
printf("这里是标签的位置!!!\n");
return 0;
}
注意事项:
- 标签后面有一个冒号
:
。 goto
语句是一个无条件跳转语句,不利于程序的可读性,一般不建议使用。goto
语句通常用于处理严重的错误,并退出程序,特别是在驱动程序和嵌入式系统开发中比较常见。
示例解析:
#include <stdio.h>
int main(int argc, char const *argv[]) {
int num = 0;
printf("请你来几拳!!!\n");
scanf("%d", &num);
while (getchar() != '\n'); // 清空标准输入缓冲区
for (int i = 0; i < num; ++i) {
goto Even; // 无条件跳转到标签为 Even 的位置
}
Even:
printf("这里是标签的位置!!!\n");
return 0;
}
- 程序开始时,提示用户输入一个整数
num
。 - 清空标准输入缓冲区后,进入
for
循环。 - 在
for
循环中,立即执行goto Even;
,跳转到Even
标签处。 - 输出
"这里是标签的位置!!!"
。 - 程序结束。
7.3 使用建议
尽量避免使用 goto
语句,因为它会使程序的控制流变得复杂,难以维护和理解。可以通过函数、循环和条件语句来实现大多数 goto
的功能。
在特殊情况下(如处理错误或异常情况)使用 goto
时,应该小心并尽量简化跳转逻辑。
加粗样式