跳到主要内容

控制流程

控制流程决定了程序的执行顺序。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 语句的执行流程:

  1. 计算表达式的值
  2. 与每个 case 的常量值比较
  3. 找到匹配的 case,执行对应代码
  4. 遇到 break 跳出 switch
  5. 没有匹配则执行 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 语句有以下限制:

  • 表达式必须是整数类型(intcharenum 等)
  • 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. 检查条件
  2. 条件为真则执行循环体
  3. 执行完毕后回到步骤 1
  4. 条件为假则退出循环

如果条件一开始就为假,循环体一次都不会执行:

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-whilewhile 的区别:

  • 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 (初始化; 条件; 迭代) {
循环体
}

执行流程:

  1. 执行初始化(只执行一次)
  2. 检查条件
  3. 条件为真则执行循环体
  4. 执行迭代语句
  5. 回到步骤 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 语言的控制流程:

  • 条件语句:ifif-elseif-else if-elseswitch
  • 循环语句:whiledo-whilefor
  • 跳转语句:breakcontinuegotoreturn
  • 嵌套循环和条件语句的组合使用

下一章将学习 函数,了解如何组织和复用代码。