编程结构介绍
C语言是一种面向过程的结构化编程语言,与C++的面向对象特性不同。结构化编程的核心思想是将复杂程序分解为三种基本结构,通过它们的组合实现任意复杂的程序逻辑。
三种基本编程结构
-
顺序结构
- 程序默认的执行方式
- 代码按照书写顺序从上到下依次执行
- 每条语句执行一次
- 最基本的程序结构,所有程序都包含顺序结构
-
选择结构(分支结构)
- 根据条件判断的结果,选择性地执行部分代码
- 实现程序的条件分支逻辑
- 包括if-else和switch-case两种主要形式
-
循环结构
- 在条件满足时重复执行特定代码段
- 实现程序的重复执行逻辑
- 包括for、while、do-while三种形式
九大控制语句(C语言关键字)
C语言通过以下9个关键字实现程序流程控制:
| 类别 | 语句 | 功能说明 |
|---|---|---|
| 选择结构 | if-else | 条件判断,二选一或多选一 |
| 选择结构 | switch-case | 多路分支选择 |
| 循环结构 | for | 计数循环,明确循环次数 |
| 循环结构 | while | 条件循环,先判断后执行 |
| 循环结构 | do-while | 条件循环,先执行后判断 |
| 跳转语句 | break | 跳出当前循环或switch结构 |
| 跳转语句 | continue | 跳过本次循环剩余部分 |
| 跳转语句 | goto | 无条件跳转(慎用) |
| 函数控制 | return | 从函数返回 |
选择结构(分支结构)
选择结构允许程序根据条件判断结果,选择执行不同的代码路径,是程序实现智能判断的基础。
if-else语句
标准格式
c
if (条件表达式) {
// 程序段1:条件为真时执行
} else {
// 程序段2:条件为假时执行
}
语法说明:
if:中文意为"如果"else:中文意为"否则"- 条件表达式:可以是任何返回数值的表达式,C语言中0为假,非0为真
- 大括号
{}:用于包含多条语句,如果只有一条语句可以省略(但不推荐)
条件表达式的真值判断
c
// 条件判断示例
if (0) // 假,0为假
if (1) // 真,非0为真
if (-1) // 真,非0为真
if (0.000001) // 真,浮点数非0为真
if (a) // 等价于 if (a != 0)
if (a == 0) // a等于0时为真
if (a = 1) // 注意:这是赋值,不是比较!总是为真(a被赋值为1,表达式值为1)
重要提醒: =是赋值运算符,==才是比较运算符,两者容易混淆但功能完全不同!
if-else多分支结构
c
// 多分支if-else结构
if (条件1) {
// 程序段1
} else if (条件2) {
// 程序段2
} else if (条件3) {
// 程序段3
} else {
// 程序段4:所有条件都不满足时执行
}
执行逻辑:
- 判断条件1,若为真则执行程序段1,然后直接结束整个if结构
- 若条件1为假,判断条件2,若为真则执行程序段2,然后结束
- 若条件2也为假,判断条件3,若为真则执行程序段3,然后结束
- 若所有条件都为假,执行else中的程序段4
if-else的省略形式
c
// 形式1:省略else分支
if (条件) {
// 条件为真时执行
}
// 条件为假时什么都不做,继续执行后续代码
// 形式2:省略大括号(单条语句)
if (条件)
statement1; // 只有这一条语句属于if结构
statement2; // 这条语句总是执行,不属于if结构
// 等价于
if (条件) {
statement1;
}
statement2;
最佳实践: 即使只有一条语句,也建议使用大括号,提高代码可读性和避免潜在错误。
if-else注意事项
- else不能单独使用,必须与if配对
- else与最近未匹配的if配对(注意嵌套时的匹配问题)
- if和else最多执行其中一个分支
- else后面不能直接跟条件表达式,如果需要条件判断应使用else if
- 使用大括号明确代码块范围,避免"悬挂else"问题
完整if-else示例
c
#include <stdio.h>
int main(void) {
char ch;
printf("请输入一个字符:\n");
scanf("%c", &ch);
if (ch >= 'a' && ch <= 'z') { // 小写字母
ch -= 32; // 转换为大写(ASCII码差32)
printf("转换为大写:%c\n", ch);
} else if (ch >= 'A' && ch <= 'Z') { // 大写字母
ch += 32; // 转换为小写
printf("转换为小写:%c\n", ch);
} else if (ch >= '0' && ch <= '9') { // 数字字符
int num = ch - '0'; // 字符数字转换为整型数字
printf("数字值:%d\n", num);
} else { // 其他字符
printf("输入的不是字母或数字\n");
}
return 0;
}
switch-case语句
switch-case是另一种实现多分支选择的结构,特别适用于基于离散值的选择。
标准格式
c
switch (整型表达式) {
case 常量1:
程序段1;
break;
case 常量2:
程序段2;
break;
case 常量3:
程序段3;
break;
default:
默认程序段;
break;
}
语法规则
- 表达式必须是整型(int、char、enum等),不能是浮点型或字符串
- case后面必须是常量表达式,不能是变量或非常量表达式
- break的作用:跳出整个switch结构
- default的作用:所有case都不匹配时执行(可省略)
- 执行流程 :
- 计算switch表达式的值
- 与各个case常量比较,找到匹配项
- 从匹配的case开始执行,直到遇到break或switch结束
- 若无匹配且存在default,执行default部分
break的省略与穿透效应
c
// 示例:根据月份判断季节
#include <stdio.h>
int main(void) {
int month;
printf("请输入月份:");
scanf("%d", &month);
printf("季节:");
switch (month) {
case 12:
case 1:
case 2:
printf("冬季\n");
break;
case 3:
case 4:
case 5:
printf("春季\n");
break;
case 6:
case 7:
case 8:
printf("夏季\n");
break;
case 9:
case 10:
case 11:
printf("秋季\n");
break;
default:
printf("月份输入错误!\n");
}
return 0;
}
注意: 故意省略break可以实现多个case共享同一段代码,但需要明确注释,避免被认为是错误。
default的位置问题
c
// default可以放在任意位置,但执行顺序总是在最后
switch (value) {
case 1:
printf("值为1\n");
break;
default: // 放在中间
printf("默认情况\n");
break;
case 2:
printf("值为2\n");
break;
}
// 实际执行顺序:
// 1. value==1 → 执行case 1
// 2. value==2 → 执行case 2
// 3. 其他值 → 执行default
完整switch-case示例
c
// 示例:月份天数查询(switch实现)
#include <stdio.h>
int main(void) {
int year, month, days;
int isLeapYear = 0;
printf("请输入年份:");
scanf("%d", &year);
printf("请输入月份:");
scanf("%d", &month);
// 判断闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
isLeapYear = 1;
}
// 使用switch判断月份天数
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:
if (isLeapYear) {
days = 29;
} else {
days = 28;
}
break;
default:
printf("月份输入错误!\n");
return -1;
}
printf("%d年%d月有%d天\n", year, month, days);
return 0;
}
switch-case的局限性
- 只能处理整型表达式,不能处理浮点数或字符串
- case值必须是常量,不能是变量或范围
- 不适合处理复杂条件逻辑,特别是包含关系运算符的条件
if-else与switch-case对比与选择
适用场景对比
| 特性 | if-else | switch-case |
|---|---|---|
| 表达式类型 | 任意表达式(返回数值) | 仅限整型表达式 |
| 条件形式 | 关系表达式、逻辑表达式等 | 与常量值相等比较 |
| 多分支处理 | 通过else if链实现 | 通过多个case实现 |
| 范围判断 | 直接支持(如 score >= 90) |
不支持,需转换 |
| 可读性 | 复杂时较差 | 离散值选择时较好 |
| 执行效率 | 条件复杂时可能较慢 | 编译优化后可能更快 |
选择原则
优先使用if-else的情况:
- 条件基于数值范围(如分数段划分)
- 条件包含关系运算符(>、<、>=、<=)
- 条件包含逻辑运算符(&&、||、!)
- 判断条件非整型(如浮点数、字符串)
- 分支数量较少(3个以下)
优先使用switch-case的情况
- 基于离散整数值的选择
- 分支数量较多(4个以上)
- 多个分支共享相同代码
- 需要编译器优化跳转表的情况
选择结构实际编程建议与常见错误
编程建议:
- 明确优先选择条件:将最可能为真的条件放在前面,提高效率
- 使用大括号:即使只有一条语句也使用大括号,提高可读性和避免错误
- 合理注释:对复杂条件逻辑添加注释说明
- 避免深度嵌套:if-else嵌套不应超过3层,过深应考虑重构
- 统一编码风格:保持缩进一致,提高代码可读性
常见错误与避免方法
c
// 错误1:误用=代替==
if (a = 5) { // 错误:这是赋值,总是为真
// ...
}
// 正确写法
if (a == 5) { // 正确:比较是否相等
// ...
}
// 错误2:悬空else问题
if (condition1)
if (condition2)
statement1;
else // 这个else与哪个if匹配?
statement2;
// 正确写法:使用大括号明确范围
if (condition1) {
if (condition2) {
statement1;
}
} else {
statement2;
}
// 错误3:switch中忘记break
switch (value) {
case 1:
printf("值为1\n");
// 忘记break,会继续执行case 2
case 2:
printf("值为2\n");
break;
}
// 错误4:case中使用变量
int var = 10;
switch (value) {
case var: // 错误:case后必须是常量
// ...
break;
}
性能优化建议:
- if-else链优化:将最可能为真的条件放在最前面
- switch优化:当case值连续时,编译器可能生成更高效的跳转表
- 避免重复计算:将多次使用的表达式结果保存到变量中
- 使用查表法:对于固定的映射关系,可以使用数组查表代替多重if-else
c
// 查表法示例:根据月份获取天数(不考虑闰年)
int monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (month >= 1 && month <= 12) {
days = monthDays[month - 1]; // 直接查表,比多个if-else更高效
}