第
5
章
选择结构
.. 5.1 概 述
在问题求解中语句的执行需要根据条件进行判断,并选择符合逻辑的语句或
者语句块来执行,具体表现形式为分支选择结构。分支选择结构的主要作用是在
顺序结构的基础上,根据条件判断结果改变代码执行顺序,使得程序能够根据不
同的情况做不同的响应。
常见的选择结构有单分支选择结构、双分支选择结构、多分支选择结构以及
嵌套分支选择结构,如图5.1所示。
图5.1 选择结构
.. 5.2 单分支选择结构
单分支选择结构语法: 
if(表达式){ 
语句; 
}
如果表达式为真(非0),则执行语句,否则不执行。
说明: 
(1)表达式可以是任何类型,常用的是关系或逻辑表达式。
(2)语句可以是一条语句或者语句块,也可以是另一个if语句。

50 程序设计与问题求解(C语言版·微课版) 
执行流程如图5.2所示。
图5.2 单分支选择结构
例5.1 输入一个整数,如果是偶数,则输出even。
判断一个整数n是否为偶数的方法是测试该整数是否为2的倍数,即n%2的结果是否
为0。根据这个结果进行相应输出,对不同的n进行不同的响应。
代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int num; 
scanf("%d",&num); 
if(num %2 == 0){ 
printf("even"); 
} 
return 0; 
}
当if中表达式成立时,说明num 是偶数,此时输出结果。本例中仅执行一条输出语句, 
可以不用{},但为提高代码的可读性,培养良好的编程规范,建议加上{}。
.. 5.3 双分支选择结构
当判断为假的分支也需要处理相应的逻辑时,可以使用双分支选择结构,相应的语句为
if-else语句,语法如下。 
if(表达式){ 
语句1; 
}else{ 
语句2; 
}

第5章 选择结构 51 
如果表达式为真(非0),则执行语句1,否则执行语句2。
图5.3 双分支选择结构
说明: 
(1)表达式可以是任何类型的,常用的是关系或逻
辑表达式。
(2)语句1和语句2可以是任何可执行语句,也可
以是另一个if-else语句。
执行流程如图5.3所示。
例5.2 输入一个字符,如果是数字字符则输出" 
digital",否则,输出"nondigital"。
对于一个字符ch,测试其ASCII是否为'0'~'9',如
果是则为数字字符,输出"digital",否则输出"non 
digital"。因为本例对于是或不是数字字符这两种情况
都需要有响应,所以需要使用if-else结构。
代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
char char; 
scanf("%c",&ch); 
if(c >= '0' && c <= '9'){ 
printf("digital"); 
}else{ 
printf("non digital"); 
} 
return 0; 
}
例5.3 输入年份,判断该年份是否为闰年。
判断年份year是否为闰年的表达式为: 
year % 4 == 0 && year % 100 != 0 || year % 400 == 0 
因为表达式中逻辑与&& 的优先级高于逻辑或||的优先级,所以先计算year%4== 
0&&year%100!=0子式,如果该子式成立,则不计算第二个子式year%400==0,否
则计算第二个子式。
为了提高程序的可读性,也可以通过()来明确子式的计算顺序: 
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 
完整代码如下: 
#include <stdio.h> 
#include <stdlib.h>

52 程序设计与问题求解(C语言版·微课版) 
int main(){ 
int year; 
scanf("%d",&year); 
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){ 
printf("%d is leap year."); 
}else{ 
printf("%d is not leap year"); 
} 
return 0; 
}
例5.4 再论鸡兔同笼。
鸡兔同笼需要求解方程组: 
x =4n -m 
2 
y =m -2n 
2 
ì
.
í
.. 
.. 
其中,n 为头的数量,m 为腿的数量。考虑到问题的特殊性,求解结果x、y 必须是整数解, 
因此,首先要判断4n-m 、m -2n 是否能够被2整除,如果能够整除,则存在合法的解,否
则,问题不存在解。
改进后的代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int n,m,x,y; 
scanf("%d %d",&n, &m); 
if((4 * n - m) % 2 == 0 && (m - 2 * n) % 2 == 0){ 
x = (4 * n - m) / 2; 
y = (m - 2 * n) / 2; 
printf("chickens:%d rabbits:%d\n",x,y); 
}else{ 
printf("No solution."); 
} 
return 0; 
}
测试1: 
35 94 
chickens:23 rabbits:12 
测试2: 
35 93 
No solution.

第5章 选择结构 53 
.. 5.4 多分支选择结构
5.4.1 elseif多分支选择结构 
多分支选择结构通过elseif多分支选择语句实现。
elseif多分
支选择结构
语法: 
if(表达式1){ 
语句1; 
}else if(表达式2){ 
语句2; 
}else if(表达式3){ 
… 
}else if(表达式n - 1){ 
语句n - 1; 
}else{ 
语句n; 
}
这种有规则的多层嵌套,又称为if语句的elseif结构。最后一个else及其下面的语句
n也可以不存在。
注意: 
(1)选择结构是从上到下匹配的,一旦匹配上某个条件后,整个条件语句就结束了,即
使后面也能匹配上条件也不会再执行了。
(2)使用if-elseif后可以不写else。
执行流程如图5.4所示。
图5.4 多分支选择结构

54 程序设计与问题求解(C语言版·微课版) 
例5.5 输入学生成绩,输出其等级。
代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int grade; 
scanf("%d",&grade); 
if(grade >= 90){ 
printf("A"); 
}else if(grade >= 80){ 
printf("B"); 
}else if(grade >= 70){ 
printf("C"); 
}else if(grade >= 60){ 
printf("D"); 
}else{ 
printf("E"); 
} 
return 0; 
}
如果第一个判断成绩成立,则不执行后续的判断,否则,执行第二个判断。如果第二个
判断不成立,则执行第三个判断,直到执行最后的else。
如果成绩为95,则第一个判断成立,输出A,后续的判断都不执行;如果输入的成绩为
65,则直到elseif(grade>=60)时判断才成立,输出D。
switch多分
支选择结构
5.4.2 switch多分支选择结构
当分支较多时,使用elseif语句的形式比较复杂,可以使用switch语句来实现,具体语
法为: 
switch(整型表达式){ 
case 常量表达式1: 
语句1; 
[break;] 
case 常量表达式2: 
语句2; 
[break;] 
… 
case 常量表达式n-1: 
语句n-1 
[break;] 
default: 
语句n 
[break;] 
}

第5章 选择结构 55 
在计算整型表达式的值后,将得到的值与每个case后的常量表达式进行比较,当表达
式的值与某个常量表达式的值相等时,执行后面的语句,直到遇到break语句为止。若表达
式的值与所有case后的常量表达式均不相同时,则执行default对应的语句。
例5.6 输入学生成绩,输出其等级(用switch语句实现)。
switch语句中用于判断的case语句判断的是一个常量,而成绩等级是一个范围,因此, 
在使用switch时要将一个成绩范围表示为一个常量。
对于一个给定的grade,执行grade=grade/10,将一个10分的区间压缩为一个常量。
如将60~69的成绩映射到6,70~79的成绩映射到7,80~89的成绩映射到8…… 
具体代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int grade; 
scanf("%d",&grade); 
grade /= 10; 
switch(grade){ 
case 10: 
case 9: printf("A"); break; 
case 8: printf("B"); break; 
case 7: printf("C"); break; 
case 6: printf("D"); break; 
case 5: 
case 4: 
case 3: 
case 2: 
case 1: 
case 0: printf("E"); break; 
} 
return 0; 
}
注意: 
(1)switch语句与if语句不同,switch仅能判断表达式的值是否等于指定的常量,而if 
可以计算并判断各种表达式。
(2)switch语句后必须为整型表达式。
(3)switch中可以有任意多的case语句,case后必须为常量。
(4)default可以省略。
(5)case和default顺序可以颠倒。
例5.7 输入一个日期(含年、月、日),计算该日期是该年度中的第几天。
根据月份计算天数,其中1、3、5、7、8、10、12月的天数为31,4、6、9、11月的天数为30 
天,2月份的天数需要根据年份判断,如果为闰年则为29天,否则为28天。
将指定月份之前所有月份的天数相加,然后加上本月的天数,如果月份大于2且为闰
年,天数加1。

56 程序设计与问题求解(C语言版·微课版) 
完整代码如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int year, month, day; 
scanf("%d-%d-%d",&year,&month,&day); 
//判断闰年 
int isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 
int days = 0; 
switch(month){ 
case 1: days = day; break; 
case 2: days = 31 + day; break; 
case 3: days = 31 + 28 + day; break; 
case 4: days = 31 + 28 + 31 + day; break; 
case 5: days = 31 + 28 + 31 + 30 + day; break; 
case 6: days = 31 + 28 + 31 + 30 + 31 + day; break; 
case 7: days = 31 + 28 + 31 + 30 + 31 + 30 + day; break; 
case 8: days = 31 + 28 + 31 + 30 + 31 + 30 + 31 + day; break; 
case 9: days = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + day; break; 
case 10: days = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + day; break; 
case 11: days = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + day; break; 
case 12: days = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + day; 
break; 
} 
if(month > 2 && isLeapYear){ 
days ++; 
} 
printf("%d-%d-%d is the %dth day of year",year,month,day,days); 
return 0; 
}
运行结果: 
2020-12-31 
2020-12-31 is the 366th day of year 
.. 5.5 嵌套分支选择结构
选择结构可以嵌套使用,即在判断正确的分支中执行的是一条选择语句。
例5.8 输入3个整数,输出最大的整数。 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int x, y, z, max;

第5章 选择结构 57 
scanf("%d,%d,%d",&x, &y, &z); 
if(x > y){ 
if(x > z) { 
max = x; 
}else{ 
max = z; 
} 
}else{ 
if(y > z){ 
max = y; 
}else{ 
max = z; 
} 
} 
printf("the max is : %d\n",max); 
return 0; 
}
注:C 语言规定了if和else的就近匹配原则,即else和最近的没有配对的if配对,与
书写格式无关。
在执行语句后面都加上{},匹配的ifelse保持相同的缩进,可以使逻辑更加清晰,且不
容易出错。
查看如下代码: 
int main(){ 
if(…) 
if(…) printf("…"); 
else printf("…"); 
return 0; 
}
代码虽然主观上将else与第一个if配对,但按照就近原则,else与第二个if配对,由此
造成了程序逻辑错误。因此,在编写代码时,尽量用{}界定范围,防止出现语法错误。
例5.6中虽然可以将百分制输出为等级制,但在边界上存在问题,即当输入-1~-9、
101~109时,程序仍然可以输出等级,因此,对于边界的成绩需要进行判断,只对合法的输
入进行等级输出,其他的成绩输出为“输入错误”,代码修改如下: 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int grade; 
scanf("%d",&grade); 
if(grade >= 0 && grade <= 100){ 
grade /= 10; 
switch(grade){ 
case 10: 
case 9: printf("A"); break;

58 程序设计与问题求解(C语言版·微课版) 
case 8: printf("B"); break; 
case 7: printf("C"); break; 
case 6: printf("D"); break; 
case 5: 
case 4: 
case 3: 
case 2: 
case 1: 
case 0: printf("E"); break; 
} 
}else{ 
printf("输入错误"); 
} 
return 0; 
} 
.. 5.6 条件表达式
条件运算符是C语言中唯一的三元运算符,需要3个运算对象,每个运算对象都是一
个表达式,如下所示: 
表达式1 ? 表达式2: 表达式3 
计算方法:如果表达式1为真,整个条件表达式的值是表达式2的值,否则,是表达式3 
的值。因此,三目运算符实际上就是一个if-else结构。
例5.9 求3个整数中的最大值。 
#include <stdio.h> 
#include <stdlib.h> 
int main(){ 
int x, y, z; 
scanf("%d,%d,%d",&x,&y,&z); 
int max = x > y ? ( x > z ? x : z) : (y > z ? y : z); 
printf("the max element is %d\n", max); 
return 0; 
}
使用嵌套的三目运算符虽然可以用少量的代码实现比较复杂的功能,但这将导致程序
的可读性大大降低,因此,不建议将三目运算符进行嵌套。
一元二次
方程求根
.. 5.7 能力拓展
5.7.1 一元二次方程求根 
给定一元二次方程f(x)=ax2+bx+c,其中a、b、c 为实数,求方程的根(精确到小数
点后6位)。