控制流程
控制流程决定了程序的执行顺序。C 语言提供了条件语句和循环语句来控制程序的执行路径。
条件语句
条件语句根据条件的真假决定执行哪个代码分支。
if 语句
if 语句在条件为真时执行代码块:
int score = 85;
if (score >= 60) {
printf("及格\n");
}
如果代码块只有一条语句,花括号可以省略,但不推荐:
if (score >= 60)
printf("及格\n"); // 不推荐省略花括号
if-else 语句
if-else 提供两个分支:
int score = 55;
if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
if-else if-else 语句
多个条件判断使用 else if:
int score = 85;
if (score >= 90) {
printf("优秀\n");
} else if (score >= 80) {
printf("良好\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
条件判断的顺序很重要:条件从上到下依次检查,一旦某个条件为真,执行对应代码块后跳出整个 if 结构。
嵌套 if 语句
if 语句可以嵌套:
int age = 25;
int score = 85;
if (age >= 18) {
if (score >= 60) {
printf("成年人且及格\n");
} else {
printf("成年人但不及格\n");
}
} else {
printf("未成年人\n");
}
嵌套层次不宜过深,否则会影响代码可读性。
悬空 else 问题
else 总是与最近的未匹配的 if 配对:
int a = 1, b = 2, c = 0;
// 缩进有误导性
if (a > 0)
if (b > 0)
c = 1;
else
c = 2; // 这个 else 实际上与内层 if 配对
// 正确的缩进
if (a > 0)
if (b > 0)
c = 1;
else
c = 2;
使用花括号可以避免这种歧义:
if (a > 0) {
if (b > 0) {
c = 1;
}
} else {
c = 2;
}
switch 语句
switch 语句根据表达式的值选择执行多个分支中的一个,适合多值判断的场景。
基本语法
int day = 3;
switch (day) {
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期日\n");
break;
default:
printf("无效的日期\n");
break;
}
switch 语句的执行流程:
- 计算表达式的值
- 与每个
case的常量值比较 - 找到匹配的
case,执行对应代码 - 遇到
break跳出 switch - 没有匹配则执行
default(如果有)
break 语句的作用
break 用于跳出 switch 结构。如果省略 break,程序会继续执行下一个 case 的代码(称为"穿透"):
int month = 2;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
printf("31天\n");
break;
case 4:
case 6:
case 9:
case 11:
printf("30天\n");
break;
case 2:
printf("28或29天\n");
break;
default:
printf("无效月份\n");
}
这种穿透特性可以用于合并多个 case。
switch 的限制
switch 语句有以下限制:
- 表达式必须是整数类型(
int、char、enum等) case的值必须是常量表达式,不能是变量case的值不能重复
int x = 10;
// 错误:case 值不能是变量
switch (x) {
case x: // 编译错误
break;
}
// 正确:case 值是常量
switch (x) {
case 10: // 正确
break;
}
循环语句
循环语句用于重复执行一段代码,直到条件不满足为止。
while 循环
while 循环在条件为真时重复执行代码块:
int i = 1;
while (i <= 5) {
printf("%d ", i);
i++;
}
// 输出: 1 2 3 4 5
执行流程:
- 检查条件
- 条件为真则执行循环体
- 执行完毕后回到步骤 1
- 条件为假则退出循环
如果条件一开始就为假,循环体一次都不会执行:
int i = 10;
while (i < 5) {
printf("这行不会执行\n");
}
do-while 循环
do-while 循环先执行一次循环体,再检查条件:
int i = 1;
do {
printf("%d ", i);
i++;
} while (i <= 5);
// 输出: 1 2 3 4 5
do-while 与 while 的区别:
while:先判断,后执行do-while:先执行,后判断
即使条件一开始就为假,do-while 也会执行一次:
int i = 10;
do {
printf("这行会执行一次\n");
} while (i < 5);
do-while 常用于需要至少执行一次的场景,如菜单选择:
int choice;
do {
printf("1. 开始游戏\n");
printf("2. 设置\n");
printf("3. 退出\n");
printf("请选择: ");
scanf("%d", &choice);
switch (choice) {
case 1: printf("开始游戏...\n"); break;
case 2: printf("打开设置...\n"); break;
case 3: printf("退出\n"); break;
default: printf("无效选择\n");
}
} while (choice != 3);
for 循环
for 循环将初始化、条件判断和迭代合并在一起:
for (int i = 1; i <= 5; i++) {
printf("%d ", i);
}
// 输出: 1 2 3 4 5
for 循环的三个部分:
for (初始化; 条件; 迭代) {
循环体
}
执行流程:
- 执行初始化(只执行一次)
- 检查条件
- 条件为真则执行循环体
- 执行迭代语句
- 回到步骤 2
for 循环的变体:
// 省略初始化(变量在外部声明)
int i = 1;
for (; i <= 5; i++) {
printf("%d ", i);
}
// 省略迭代(在循环体内迭代)
for (int i = 1; i <= 5; ) {
printf("%d ", i);
i++;
}
// 省略条件(无限循环)
for (int i = 1; ; i++) {
if (i > 5) break;
printf("%d ", i);
}
// 无限循环
for (;;) {
// 需要用 break 退出
}
嵌套循环
循环可以嵌套,常用于处理多维数据:
// 打印乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
printf("%d*%d=%d\t", j, i, i * j);
}
printf("\n");
}
输出:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
...
跳转语句
跳转语句用于改变程序的正常执行流程。
break 语句
break 用于跳出循环或 switch:
// 找到第一个能被 7 整除的数
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
printf("找到: %d\n", i);
break; // 跳出循环
}
}
在嵌套循环中,break 只跳出最内层循环:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) break; // 只跳出内层循环
printf("i=%d, j=%d\n", i, j);
}
}
continue 语句
continue 用于跳过本次循环的剩余代码,直接进入下一次迭代:
// 打印 1-10 中的奇数
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
printf("%d ", i);
}
// 输出: 1 3 5 7 9
continue 在不同循环中的行为:
// while 循环
int i = 0;
while (i < 10) {
i++;
if (i % 2 == 0) continue;
printf("%d ", i);
}
// for 循环
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) continue;
printf("%d ", i);
}
注意:在 while 循环中使用 continue 时,要确保迭代语句在 continue 之前执行,否则可能导致死循环。
goto 语句
goto 用于无条件跳转到标签:
int i = 0;
start:
i++;
printf("%d ", i);
if (i < 5) {
goto start;
}
// 输出: 1 2 3 4 5
goto 的合理使用场景:
// 错误处理:统一清理资源
int* arr = malloc(100 * sizeof(int));
FILE* file = fopen("data.txt", "r");
if (arr == NULL) {
goto cleanup_file;
}
if (file == NULL) {
goto cleanup_arr;
}
// 正常处理...
cleanup_arr:
free(arr);
cleanup_file:
if (file) fclose(file);
goto 只能在同一函数内跳转,不能跨函数。滥用 goto 会使代码难以理解和维护,应谨慎使用。
return 语句
return 用于从函数返回,可以携带返回值:
int find_first_negative(int arr[], int size) {
for (int i = 0; i < size; i++) {
if (arr[i] < 0) {
return i; // 找到后立即返回
}
}
return -1; // 未找到
}
在 main 函数中,return 0 表示程序正常结束。
循环选择指南
| 循环类型 | 适用场景 |
|---|---|
while | 不确定循环次数,先判断后执行 |
do-while | 至少执行一次,如菜单、输入验证 |
for | 已知循环次数,或需要遍历序列 |
示例对比:
// while:读取输入直到特定值
int num;
scanf("%d", &num);
while (num != 0) {
printf("读取到: %d\n", num);
scanf("%d", &num);
}
// do-while:验证输入
int password;
do {
printf("请输入密码: ");
scanf("%d", &password);
} while (password != 1234);
// for:遍历数组
int arr[] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
实例:猜数字游戏
综合运用条件语句和循环:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand(time(NULL)); // 设置随机种子
int target = rand() % 100 + 1; // 1-100 的随机数
int guess;
int attempts = 0;
printf("猜数字游戏(1-100)\n");
printf("输入 0 退出游戏\n\n");
while (1) {
printf("请输入你的猜测: ");
scanf("%d", &guess);
attempts++;
if (guess == 0) {
printf("游戏结束,答案是 %d\n", target);
break;
}
if (guess < 1 || guess > 100) {
printf("请输入 1-100 之间的数字\n");
continue;
}
if (guess < target) {
printf("太小了,再试一次\n");
} else if (guess > target) {
printf("太大了,再试一次\n");
} else {
printf("恭喜你猜对了!用了 %d 次\n", attempts);
break;
}
}
return 0;
}
小结
本章介绍了 C 语言的控制流程:
- 条件语句:
if、if-else、if-else if-else、switch - 循环语句:
while、do-while、for - 跳转语句:
break、continue、goto、return - 嵌套循环和条件语句的组合使用
下一章将学习 函数,了解如何组织和复用代码。