控制流
条件判断、循环结构及其控制语句。
1. 条件判断 (Selection)
1.1 if-else 结构
1.1.1 基本用法
if-else 结构是最基本的条件控制语句,用于根据条件执行不同的代码块。
#include <stdio.h>
int main() {
int score = 85;
if (score >= 90) {
printf("Excellent\n");
} else if (score >= 80) {
printf("Very Good\n");
} else if (score >= 60) {
printf("Pass\n");
} else {
printf("Fail\n");
}
return 0;
}
1.1.2 嵌套 if-else
#include <stdio.h>
int main() {
int age = 18;
int has_license = 1;
if (age >= 18) {
if (has_license) {
printf("You can drive\n");
} else {
printf("You need a license to drive\n");
}
} else {
printf("You are too young to drive\n");
}
return 0;
}
1.1.3 条件表达式的简写
#include <stdio.h>
int main() {
int a = 10, b = 20;
// 简单的条件判断可以使用三目运算符
int max = (a > b) ? a : b;
printf("Max: %d\n", max);
// 条件表达式作为函数参数
printf("Result: %s\n", (a > b) ? "a is larger" : "b is larger");
return 0;
}
1.2 switch-case 结构
1.2.1 基本用法
switch-case 结构用于多分支选择,比嵌套的 if-else 更清晰。
#include <stdio.h>
int main() {
char grade = 'B';
switch (grade) {
case 'A':
printf("Great!\n");
break;
case 'B':
printf("Good!\n");
break;
case 'C':
printf("Average\n");
break;
case 'D':
printf("Below Average\n");
break;
case 'F':
printf("Fail\n");
break;
default:
printf("Unknown grade\n");
}
return 0;
}
1.2.2 整数类型的 switch
#include <stdio.h>
int main() {
int day = 3;
switch (day) {
case 1:
printf("Monday\n");
break;
case 2:
printf("Tuesday\n");
break;
case 3:
printf("Wednesday\n");
break;
case 4:
printf("Thursday\n");
break;
case 5:
printf("Friday\n");
break;
case 6:
case 7:
printf("Weekend\n");
break;
default:
printf("Invalid day\n");
}
return 0;
}
1.2.3 switch 中的穿透现象
当 case 语句后没有 break 时,会发生穿透现象,继续执行下一个 case。
#include <stdio.h>
int main() {
int month = 2;
int days;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
case 2:
days = 28; // 简化处理,未考虑闰年
break;
default:
days = 0;
printf("Invalid month\n");
}
if (days > 0) {
printf("Month %d has %d days\n", month, days);
}
return 0;
}
2. 循环结构 (Iteration)
2.1 for 循环
2.1.1 基本用法
for 循环常用于已知循环次数的场景,结构清晰。
#include <stdio.h>
int main() {
// 基本 for 循环
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
printf("\n");
// 循环变量初始化、条件、增量都可以省略
int j = 0;
for (; j < 10;) {
printf("%d ", j);
j++;
}
printf("\n");
return 0;
}
2.1.2 嵌套 for 循环
#include <stdio.h>
int main() {
// 打印乘法表
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");
}
return 0;
}
2.1.3 特殊的 for 循环用法
#include <stdio.h>
int main() {
// 使用多个循环变量
for (int i = 0, j = 10; i < j; i++, j--) {
printf("i=%d, j=%d\n", i, j);
}
// 无限循环
// for (;;) {
// // 循环体
// }
return 0;
}
2.2 while 循环
2.2.1 基本用法
while 循环适用于循环次数不确定的场景,只要条件为真就继续执行。
#include <stdio.h>
int main() {
int i = 0;
while (i < 10) {
printf("%d ", i);
i++;
}
printf("\n");
return 0;
}
2.2.2 输入验证
#include <stdio.h>
int main() {
int age;
printf("Enter your age: ");
// 验证输入是否为有效年龄
while (1) {
scanf("%d", &age);
if (age >= 0 && age <= 120) {
break;
}
printf("Invalid age. Please enter again: ");
}
printf("Your age is %d\n", age);
return 0;
}
2.2.3 无限循环
#include <stdio.h>
int main() {
int count = 0;
// 无限循环,直到满足条件跳出
while (1) {
printf("Count: %d\n", count);
count++;
if (count >= 5) {
break;
}
}
return 0;
}
2.3 do-while 循环
2.3.1 基本用法
do-while 循环保证循环体至少执行一次,适用于需要先执行后判断的场景。
#include <stdio.h>
int main() {
int i = 10;
do {
printf("Execute once\n");
i--;
} while (i < 5);
return 0;
}
2.3.2 菜单驱动程序
#include <stdio.h>
int main() {
int choice;
do {
printf("\nMenu:\n");
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("3. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("You selected Option 1\n");
break;
case 2:
printf("You selected Option 2\n");
break;
case 3:
printf("Exiting...\n");
break;
default:
printf("Invalid choice\n");
}
} while (choice != 3);
return 0;
}
3. 循环控制语句 (Control Statements)
3.1 break 语句
3.1.1 基本用法
break 语句用于立即退出当前循环,不再执行循环体中剩余的语句。
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 当 i 等于 5 时退出循环
}
printf("%d ", i);
}
printf("\nLoop exited\n");
return 0;
}
3.1.2 跳出嵌套循环
#include <stdio.h>
int main() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("i=%d, j=%d\n", i, j);
if (i == 2 && j == 2) {
goto exit_loop; // 使用 goto 跳出多层循环
}
}
}
exit_loop:
printf("Exited nested loops\n");
return 0;
}
3.2 continue 语句
3.2.1 基本用法
continue 语句用于跳过本次循环的剩余部分,直接进入下一次迭代。
#include <stdio.h>
int main() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
printf("%d ", i);
}
printf("\n");
return 0;
}
3.2.2 跳过特定条件
#include <stdio.h>
int main() {
int numbers[] = {1, 2, 3, 0, 4, 5, 0, 6};
int size = sizeof(numbers) / sizeof(numbers[0]);
for (int i = 0; i < size; i++) {
if (numbers[i] == 0) {
printf("Skipping zero\n");
continue;
}
printf("Number: %d\n", numbers[i]);
}
return 0;
}
3.3 goto 语句
3.3.1 基本用法
goto 语句用于无条件跳转到指定的标签位置,一般不推荐使用,但在某些场景下可以简化代码。
#include <stdio.h>
int main() {
int i = 0;
start:
printf("i = %d\n", i);
i++;
if (i < 5) {
goto start;
}
printf("Loop completed\n");
return 0;
}
3.3.2 跳过多层循环
#include <stdio.h>
int main() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
printf("i=%d, j=%d, k=%d\n", i, j, k);
if (i == 1 && j == 1 && k == 1) {
goto end_of_loops;
}
}
}
}
end_of_loops:
printf("Exited all loops\n");
return 0;
}
3.3.3 错误处理
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file;
file = fopen("nonexistent.txt", "r");
if (file == NULL) {
perror("Error opening file");
goto cleanup;
}
// 处理文件...
fclose(file);
cleanup:
printf("Program completed\n");
return 0;
}
4. 控制流的最佳实践
4.1 代码风格建议
- 缩进一致: 使用 4 空格或 1 制表符的缩进
- 大括号使用: 始终使用大括号包围循环体和条件块
- 命名规范: 使用有意义的变量名
- 注释: 为复杂的条件和循环添加注释
- 换行: 在适当的地方换行,保持代码可读性
4.2 性能优化建议
- 循环不变量外提: 将循环中不变的计算移到循环外
- 减少循环内操作: 尽量减少循环体内的计算量
- 选择合适的循环类型: 根据具体场景选择
for、while或do-while - 避免死循环: 确保循环条件最终能为假
- 使用
break和continue: 合理使用这些语句提高循环效率
4.3 常见错误避免
- 无限循环: 确保循环条件有终止的可能
- 嵌套过深: 避免超过 3 层的嵌套,考虑重构为函数
- 条件判断错误: 注意运算符优先级和逻辑关系
- 边界条件: 处理好循环的边界情况
- 变量作用域: 合理控制变量的作用域
4.4 最佳实践示例
#include <stdio.h>
// 计算斐波那契数列
void fibonacci(int n) {
if (n <= 0) {
printf("Invalid input\n");
return;
}
int a = 0, b = 1;
printf("Fibonacci sequence: ");
for (int i = 0; i < n; i++) {
printf("%d ", a);
int next = a + b;
a = b;
b = next;
}
printf("\n");
}
// 查找数组中的元素
int find_element(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 找到元素,返回索引
}
}
return -1; // 未找到元素
}
int main() {
// 调用斐波那契函数
fibonacci(10);
// 测试查找函数
int numbers[] = {10, 20, 30, 40, 50};
int size = sizeof(numbers) / sizeof(numbers[0]);
int target = 30;
int index = find_element(numbers, size, target);
if (index != -1) {
printf("Element %d found at index %d\n", target, index);
} else {
printf("Element %d not found\n", target);
}
return 0;
}
5. 常见问题与解决方案
5.1 无限循环
问题: 循环条件永远为真,导致程序陷入无限循环
解决方案: 确保循环条件最终能为假,或使用 break 语句退出循环
// 错误示例
while (1) {
printf("This will run forever\n");
}
// 正确示例
int count = 0;
while (1) {
printf("Count: %d\n", count);
count++;
if (count >= 10) {
break;
}
}
5.2 循环条件错误
问题: 循环条件设置错误,导致循环执行次数不符合预期 解决方案: 仔细检查循环条件,确保逻辑正确
// 错误示例:应该是 i < 10,而不是 i <= 10
for (int i = 0; i <= 10; i++) {
printf("%d ", i); // 会打印 0-10,共 11 个数
}
// 正确示例
for (int i = 0; i < 10; i++) {
printf("%d ", i); // 打印 0-9,共 10 个数
}
5.3 边界条件处理
问题: 循环的边界条件处理不当,导致数组越界或其他错误 解决方案: 确保循环变量在有效范围内
// 错误示例:可能导致数组越界
int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i <= 5; i++) {
printf("%d ", arr[i]); // 访问 arr[5] 越界
}
// 正确示例
int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
5.4 switch 语句缺少 break
问题: case 语句后缺少 break,导致穿透现象
解决方案: 为每个 case 语句添加 break,除非需要穿透
// 错误示例:缺少 break
switch (grade) {
case 'A':
printf("Great!\n");
case 'B':
printf("Good!\n"); // 当 grade 为 'A' 时也会执行
break;
}
// 正确示例
switch (grade) {
case 'A':
printf("Great!\n");
break;
case 'B':
printf("Good!\n");
break;
}
5.5 嵌套过深
问题: 循环和条件嵌套过深,代码可读性差 解决方案: 将嵌套的代码重构为函数
// 嵌套过深的示例
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
for (int j = 0; j < 5; j++) {
if (j > 2) {
// 处理逻辑
}
}
}
}
// 重构为函数
void process_even(int i) {
for (int j = 0; j < 5; j++) {
if (j > 2) {
// 处理逻辑
}
}
}
// 主函数
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
process_even(i);
}
}
6. 控制流的高级应用
6.1 循环的替代方案
6.1.1 使用 goto 实现循环
#include <stdio.h>
int main() {
int i = 0;
loop:
if (i < 10) {
printf("%d ", i);
i++;
goto loop;
}
printf("\n");
return 0;
}
6.1.2 使用递归代替循环
#include <stdio.h>
void print_numbers(int n) {
if (n < 0) {
return;
}
print_numbers(n - 1);
printf("%d ", n);
}
int main() {
print_numbers(9);
printf("\n");
return 0;
}
6.2 复杂条件的处理
6.2.1 使用逻辑运算符组合条件
#include <stdio.h>
int main() {
int age = 25;
int has_license = 1;
int has_car = 1;
// 复杂条件
if (age >= 18 && has_license && has_car) {
printf("You can drive\n");
} else if (age >= 18 && has_license) {
printf("You can drive if you have a car\n");
} else if (age >= 18) {
printf("You need a license to drive\n");
} else {
printf("You are too young to drive\n");
}
return 0;
}
6.2.2 使用布尔函数简化条件
#include <stdio.h>
int is_even(int n) {
return n % 2 == 0;
}
int is_positive(int n) {
return n > 0;
}
int main() {
int number = 4;
if (is_even(number) && is_positive(number)) {
printf("%d is a positive even number\n", number);
}
return 0;
}
6.3 状态机的实现
#include <stdio.h>
int main() {
enum State {
STATE_START,
STATE_READING,
STATE_PROCESSING,
STATE_FINISHED
};
enum State current_state = STATE_START;
int data_processed = 0;
int max_data = 5;
while (current_state != STATE_FINISHED) {
switch (current_state) {
case STATE_START:
printf("Starting process\n");
current_state = STATE_READING;
break;
case STATE_READING:
printf("Reading data\n");
current_state = STATE_PROCESSING;
break;
case STATE_PROCESSING:
printf("Processing data %d\n", data_processed);
data_processed++;
if (data_processed >= max_data) {
current_state = STATE_FINISHED;
} else {
current_state = STATE_READING;
}
break;
case STATE_FINISHED:
printf("Process finished\n");
break;
}
}
return 0;
}
7. 代码优化技巧
7.1 循环优化
7.1.1 减少循环内计算
// 优化前
for (int i = 0; i < strlen(s); i++) {
// 每次循环都计算 strlen(s)
}
// 优化后
int len = strlen(s);
for (int i = 0; i < len; i++) {
// 只计算一次 strlen(s)
}
7.1.2 使用递增而非递减
// 优化前
for (int i = n; i >= 0; i--) {
// 循环体
}
// 优化后(某些架构上更高效)
for (int i = 0; i <= n; i++) {
// 循环体
}
7.1.3 展开循环
// 优化前
for (int i = 0; i < 4; i++) {
process(i);
}
// 优化后(展开循环)
process(0);
process(1);
process(2);
process(3);
7.2 条件优化
7.2.1 利用短路求值
// 优化前
if (ptr != NULL) {
if (ptr->value == 5) {
// 处理逻辑
}
}
// 优化后
if (ptr != NULL && ptr->value == 5) {
// 处理逻辑
}
7.2.2 条件顺序优化
// 优化前(假设 ptr == NULL 的概率较高)
if (ptr->value == 5 && ptr != NULL) {
// 可能会崩溃
}
// 优化后
if (ptr != NULL && ptr->value == 5) {
// 更安全,利用短路求值
}
7.3 控制流优化示例
#include <stdio.h>
// 优化前:多个 if-else 嵌套
int get_grade_point(char grade) {
if (grade == 'A') {
return 4;
} else if (grade == 'B') {
return 3;
} else if (grade == 'C') {
return 2;
} else if (grade == 'D') {
return 1;
} else {
return 0;
}
}
// 优化后:使用 switch 语句
int get_grade_point_optimized(char grade) {
switch (grade) {
case 'A': return 4;
case 'B': return 3;
case 'C': return 2;
case 'D': return 1;
default: return 0;
}
}
int main() {
char grade = 'B';
printf("Grade point: %d\n", get_grade_point(grade));
printf("Grade point (optimized): %d\n", get_grade_point_optimized(grade));
return 0;
}
更新日志 (Changelog)
- 2026-04-05: 拆分控制流详解
- 2026-04-05: 扩写内容,增加详细的代码示例、使用方法、最佳实践和常见问题解决方案