第5章 分 支 结 构 学习目标 正确地判断和使用逻辑表达式和关系表达式; 掌握各种形式if语句的语法和用法,注意嵌套if结构中if和else的匹配关系; 掌握switch语句语法和使用方法,注意switch语句的控制流程; 掌握switch语句中break语句的使用以及switch语句的嵌套; 熟练使用if结构和switch结构解决简单的应用问题。 5.1if结构 在日常生活中大家可能经常遇到这样的问题,如果今天天气好我就出去郊游,否则就在家看电视。对于这种需要根据不同情况执行不同操作的问题,计算机该如何处理?顺序语句只能按照语句的先后顺序来运行,显然不能根据判断结果 选择处理方式,这要求程序本身具有判断能力。本章介绍的分支结构正是为解决这一类问题而设定的。本章将会介绍C语言中的几种分支结构,包括if结构和switch结构。 if结构是最常见的分支结构,if语句是单分支结构,ifelse构成双分支结构,同时可以利用if语句或者ifelse语句的嵌套实现多分支结构。 5.1.1if语句 if语句是最简单的分支语句,是一种单分支结构,其语法形式为: 图51if结构的 流程图 if(<表达式>) { <语句A> } 上述结构中的<表达式>一般为条件表达式或者逻辑表达式,用一对小括号括起来。if语句的功能是先判断<表达式>的逻辑值,若该逻辑值是“真”,则进入分支运行<语句A>,否则什么也不运行。式中,<语句A>是分支语句,可以是一条语句也可以是多条语句,如果分支结构只有一条语句。则大括号可以省略。 if结构的流程图如图51所示。 【例51】若有定义int a=3,b=1;,判断下列表达式逻辑值真假。 a>0a>=0a>ba==ba!=ba==1a=1 a=ba=0a&&ba||b!a!b--!--b 分析: a>0为真,a>=0为真,a>b为真,a==b为假,a!=b为真,a==1为假,a=1为真,a=b为真,a=0为假,a&&b为真,a||b为真,!a为假,!b--为假,!--b为真。 注意: 一个等号表示赋值,两个等号表示比较大小。a=b,则a的值由3变为1; a==b是判断a和b的值是否相等,相等则结果为1,不等则结果为0。 【例52】从键盘任意输入一个实数a,求其绝对值并输出。 分析: 根据题目要求,当a是负数时,需要求其相反数; 当a为非负数,则不需要做任何改变。 1#include<stdio.h>//包含头文件stdio.h,因为用到输入输出函数 2void main(){//主函数名字固定为main 3float a;//定义单精度浮点型变量,可以存小数 4printf("请输入一个实数: ");//在屏幕上输出提示 5scanf("%f", &a);//从键盘输入一个浮点数,存到变量a中 6if (a < 0)//判断输入的数小于0 7{ 8a = -a;//负数变为正数 9} 10printf("a的绝对值为: %f\n", a);//输出绝对值数值 11} 运行结果: 第三次提示: 如果使用VC 2010环境,可在main函数体语句最后面,结尾大括号前面,增加getchar();语句,避免画面一闪而过。 5.1.2ifelse语句 ifelse语句是由关键字if和else构成的二分支结构,其语法形式为: if(<表达式>) { <语句A> } else { <语句B> } 上述结构中的<表达式>一般为条件表达式或者逻辑表达式,用一对小括号括起来。ifelse语句的功能是先判断<表达式>的逻辑值,若该逻辑值是“真”,则运行<语句A>,否则运行<语句B>。式中,<语句A>、<语句B>都是分支语句,可以是一条语句也可以是多条语句,如果只有一条语句,则大括号可以省略。一次条件判断结束,<语句A>、<语句B>只可能运行其一,不可能同时都运行。 ifelse结构的流程图如图52所示。 图52ifelse结构流程图 【例53】从键盘输入一个整数n,判断该数的奇偶,如果n是偶数输出“n是偶数”; 如果n不是偶数输出“n是奇数”。 分析: 根据题目要求,判断n是否为偶数,也就是n除以2的余数是否为0。根据不同的结果需要输出不同的信息,很显然应该使用二分支结构。 1#include<stdio.h>//包含头文件stdio.h,因为用到输入输出函数 2void main(){//主函数名字固定为main,返回值为空值 3int n;//定义变量 4printf("请输入一个整数: "); //在屏幕上输出提示 5scanf("%d", &n);//从键盘输入一个整数,存入变量n中 6if (n%2==0)//余数等于0则为真,不等于0则为假 7{printf("%d是偶数\n", n); } 8else 9{printf("%d是奇数\n", n); } 10} 运行结果: 上述程序也可以写成这样,观察一下判断条件的变化。 1#include<stdio.h> 2void main(){ 3int n; 4printf("请输入一个整数: "); 5scanf("%d", &n); 6if (n%2)//余数为1则为真,余数为0则为假 7{printf("%d是奇数\n", n);} 8else 9{printf("%d是偶数\n", n);} 10} 【例54】编写程序,通过输入x的值,计算分段函数y的值。 y=x,x≥0 x2,x<0 分析: 根据题目要求,对于输入的x值要进行判断,在x<0和x≥0的情况下,y的取值不同。 1#include<stdio.h> 2void main(){ 3float x, y; 4printf("请输入一个实数: "); 5scanf("%f", &x);//读入一个单精度浮点数 6if (x<0) 7{y=x*x;} 8else 9{y=x;} 10printf("y=%f\n", y); 11} 运行结果: 5.1.3if语句的嵌套 if语句的嵌套是指在if或者else的分支结构中包含另外的if语句或者ifelse语句,也就是前面所述的if结构中<语句A>、<语句B>可以是if语句或者ifelse语句。if语句的嵌套层次原则上可以是任意多层,但通常情况下不建议使用层数较多的嵌套。if语句的嵌套形式一般分为两种: 规则嵌套和不规则嵌套。 1. 规则嵌套 规则嵌套是每一层的if或else分支嵌套着另一个ifelse结构。其语法形式如下: if(<表达式1>) { <语句A> } else if(<表达式2>) { <语句B> } else if(<表达式3>) { <语句C> } … else if(<表达式n>) { <语句X> } else { <语句X+1> } 上述结构的功能是先判断<表达式1>的逻辑值,若该逻辑值是“真”,则运行<语句A>,否则判断<表达式2>的逻辑值,若为“真”,则运行<语句B>,否则继续判断<表达式3>的逻辑值……以此类推。 规则嵌套的流程图如图53所示。 图53ifelse的规则嵌套流程图 【例55】编写程序,通过输入x的值,计算分段函数y的值。 y= x(x<1) 2x-1(1≤x<10) 3x-1(x≥10) 分析: 根据题目要求,对于输入的x值要进行判断。在 x<1、1≤x<10和x≥10三种情况下,y值的计算公式不同。 1#include<stdio.h> 2void main() 3{ 4float x, y; 5printf("请输入一个实数: "); 6scanf("%f",&x); 7if(x<1) 8{ y=x;} 9else if(x<10) 10{y=2*x-1;} 11else 12{y=3*x-1;} 13printf("y的值为: %f\n", y); 14} 运行结果: 问题: else if语句中为何不需要写为x>=1 && x<10,却只写 x<10条件? 【例56】从键盘输入学生百分制成绩score,输出成绩等级A、B、C、D。A等为85分以上,B等为70~84分,C等为60~69分,D等为60分以下。 分析: 将百分制成绩分为4个等级输出,需要进行多层判断。 1#include<stdio.h> 2void main() 3{ 4int score; 5printf("请输入一个百分制成绩: "); 6scanf("%d",&score); 7if(score>=0&&score<=100) 8{ 9if(score>=85) 10{ 11printf("成绩为A等\n"); 12}else if(score>=70) 13{ 14printf("成绩为B等\n"); 15}else if(score>=60) 16{ 17printf("成绩为C等\n"); 18}else 19{ 20printf("成绩为D等\n"); 21} 22}else 23printf("您输入的不是百分制分数\n"); 24} 运行结果: 在使用ifelse嵌套结构时需要注意以下几点。 (1) C语言规定,else总是与在它上面、距它最近且尚未匹配的if配对。 (2) 程序书写采用缩进方式,将同一层的分支结构对齐,这样可以增加程序的美观性和可读性。 (3) 程序设计时,ifelse结构不宜太多,2~3层左右,否则对程序的运行效率会有所影响。 2. 任意嵌套 与规则嵌套不同,任意嵌套是在ifelse结构中的任一分支中嵌入if结构或者ifelse结构。实际问题中,大部分都是任意嵌套的形式。 对于初学者来说,多重ifelse结构最容出错的就是if与else的配对问题。建议大家在编写程序时,先写好分支结构的左右大括号,再在大括号中间编写分支语句或者其他的分支结构,避免遗漏右边大括号造成的程序错误。同时建议,对于只有一条语句的分支也不要省略大括号,避免出现不必要的逻辑错误。 【例57】试比较下列两段程序的差异。 程序一: #include<stdio.h> void main() { int a=1,b=-1; if(a>0) if(b>0) a++; else a--; printf("a=%d\n",a); } 运行结果: a=0 程序二: #include<stdio.h> void main() { int a=1,b=-1; if(a>0) { if(b>0) a++; } else a--; printf("a=%d\n",a); } 运行结果: a=1 5.2switch结构 通过上面的学习我们了解到,对于多种分支的情况,我们可以采用if语句和ifelse语句的多重嵌套来实现。但是如果需要判断的分支很多,嵌套层次就会变得复杂,而且程序运行效率会降低。为了解决这个问题,C语言提供了switch语句专门处理多路分支的情形。 switch语句是一种多路分支语句,其语法形式如下: switch(<表达式>) { case <值1>: 语句序列1; break; case <值2>: 语句序列2; break; … case <值n-1>: 语句序列n-1; break; case <值n>: 语句序列n; break; default: 语句序列n+1; } 其运行过程为: 当switch后面的<表达式>的值与某个case后面的“值i”相同时,就运行case后面的语句序列i; 当运行到break语句时,跳出switch语句,运行后面的程序语句。如果没有任何一个case后面的值与<表达式>的值相等,则运行default后面的语句序列,直到switch语句结束。 switch结构可以没有default标号,此时如果没有任何一个case后面的值与<表达式>的值相等,则直接跳出switch结构。 switch语句运行的流程图如图54所示。 图54switch语句流程图 【例58】输入成绩等级A、B、C、D,要求按照考试成绩的等级输出百分制分数段。A等为85分以上,B等为70~84分,C等为60~69分,D等为60分以下。 分析: 这是一个多分支选择问题,根据4个等级输出对应的百分制分数范围。如果用if语句来至少要三层的嵌套,使用switch则只需一次匹配即可。 1#include<stdio.h> 2void main(){ 3char grade; 4printf("请输入一个成绩等级: "); 5scanf("%c",&grade);//读入一个字符 6switch(grade)//switch多分支 7{ 8case 'A': printf("85-100\n");break; 9case 'B': printf("70-84\n");break; 10case 'C': printf("60-69\n");break; 11case 'D': printf("60以下\n");break; 12default:printf("输入错误!\n"); 13} 14} 运行结果: 在使用switch语句时还应注意以下几点。 (1) switch后面的<表达式>,一般是int型、char型和枚举型中的一种,不能是float型或者double型。同时,每个case后面“值”的类型应该与switch后面的<表达式>的类型一致。 (2) case后面的语句序列可以是一条语句也可以是多条语句,但语句序列的大括号可以省略,如: switch(i){ case 1:{ a++;b++;break;}//{}可省略 case 2:a--;b--;break;//省略了{} default:break; } (3) 每个case后面的数值必须各不相同,否则会出现相互矛盾的现象。因为对<表达式>的同一值,不允许有两种或以上的运行方案。 (4) 每个case后面的数值必须是常量或者是常量表达式,不能包含变量。 (5) case后面的数值仅起语句标号作用,并不进行条件判断。系统一旦找到入口标号,就从此标号开始运行,不再进行标号判断,直到遇见break语句跳出,或者运行到switch语句结束。例如,在例58中,如果去掉各个case子句中的break语句,将连续输出,效果如下。 1#include<stdio.h> 2void main(){ 3char grade; 4printf("请输入一个成绩等级: "); 5scanf("%c",&grade); 6switch(grade) 7{ 8case 'A':printf("85-100\n"); 9case 'B':printf("70-84\n"); 10case 'C':printf("60-69\n"); 11case 'D':printf("60以下\n"); 12default:printf("输入错误!\n"); 13} 14} 运行结果: 提示: 如果case子句和default子句都带有break语句,那么它们之间的顺序不影响switch分支的功能。如果case子句和default子句有的带有break语句,有的没有,那么它们之间的顺序变化可能会影响输出结果。 5.3程 序 范 例 【例59】已知某公司员工的保底月薪为1500,某月所接工程的绩效profit(整数)与绩效提成的关系如下所示,计算员工的当月薪水。 工程绩效profit提成比率 profit<1000没有提成 1000<=profit<200010% 2000<=profit<500015% 5000<=profit<1000020% profit>=1000025% 分析: 这是一个典型的多分支问题,员工最终的薪水=保底月薪+工程绩效*提成比率,可以使用ifelse的嵌套结构,也可以使用switch结构。 方法一: 1#include<stdio.h>//包含头文件 2void main()//主函数 3{ 4int profit;//定义变量 5float salary=0; 6printf("请输入当月绩效: "); 7scanf("%d",&profit);//输入绩效 8if(profit<1000)//1000以下没有提成 9{ 10salary = 1500; 11}else if(profit<2000)//大于等于1000,小于2000,提成10% 12{ 13salary = 1500+profit*0.1; 14}else if(profit<5000)//大于等于2000,小于5000,提成15% 15{ 16salary = 1500+profit*0.15; 17}else if(profit<10000)//大于等于5000,小于10000,提成20% 18{ 19salary = 1500+profit*0.2; 20}else//大于等于10000,提成25% 21{ 22salary = 1500+profit*0.25; 23} 24printf("当月薪水为: %.2f",salary);//输出薪水 25} 运行结果: 方法二: 使用switch语句,需要对profit值判断,但是profit可能是很大的值,不可能在程序中一一穷举。分析本题可知,提成的变化都是1000的整数倍,我们可以将profit值除以1000再进行匹配。 1#include<stdio.h> 2void main() 3{ 4int profit; 5float salary=0; 6printf("请输入当月绩效: "); 7scanf("%d",&profit); 8switch(profit/1000)//判断绩效除以1000的值 9{ 10case 0: salary=1500; break;//1000以下没有提成 11case 1: salary=1500+profit*0.1;break;//1000=<绩效<2000,提成10% 12case 2: 13case 3: 14case 4: salary=1500+profit*0.15;break; //2000=<绩效<3000,提成15% 15case 5: 16case 6: 17case 7: 18case 8: 19case 9: salary=1500+profit*0.2;break; //5000=<绩效<10000,提成20% 20default: salary=1500+profit*0.25;//绩效大于10000,提成25% 21} 22printf("当月薪水为: %.2f",salary); 23} 运行结果: 提示: 不是所有的多分支都能用switch语句,能枚举每一个可能取值才能用switch语句,但所有的多分支都可以用嵌套ifelse语句实现。 【例510】写一程序,从键盘输入年份year,判断其是否为闰年。闰年的条件是: 能被4整除但不能被100整除,或者能被400整除。 分析: 如果X能被Y整除,则余数为0,即X%Y==0。 1#include<stdio.h> 2void main() 3{ 4int year; 5printf("请输入年份: "); 6scanf("%d", &year); 7if(year%4 == 0 && year%100 != 0)//能被4整除,不能被100整数 8{ 9printf("%d是闰年\n", year); 10}else if(year%400 == 0)//能被400整除 11{ 12printf("%d是闰年\n", year); 13}else 14{ 15printf("%d不是闰年\n", year); 16} 17} 运行结果: 本 章 小 结 程序设计三种基本结构是: 顺序结构、分支结构、循环结构。C语言中分支结构通过ifelse语句和switch语句实现。 ifelse语句可以实现单分支和双分支结构,使用嵌套ifelse结构可以实现多分支。 switch语句可以实现多分支结构,但不是所有的多分支都可以用switch结构实现。switch结构中要注意用好break语句。 ifelse语句和switch语句可以嵌套使用。 习题 一、 选择题 1. 以下程序的运行结果是()。 #include <stdio.h> int main() { int m=5; if (m++>5) printf ("%d\n", m); elseprintf ("%d\n", m--);} A. 4B. 5C. 6D. 7 2. 以下程序的运行结果为()。 int a=1, b=2, c=2, t=0; if(a<b) {t=a;a=b;b=t;c++;} printf("%d, %d, %d",a, b, c); A. 1, 2, 0B. 2, 1, 0 C. 1, 2, 1D. 2, 1, 3 3. 设有int a=1, b=2, c=3, d=4, m=2, n=2;,运行(m=a>b)&&(n=c>d)后n的值是()。 A. 1B. 2 C. 3D. 4 4. 对if语句中表达式的类型,下面说法正确的是()。 A. 必须是关系表达式B. 必须是关系表达式或逻辑表达式 C. 必须是关系表达式或算术表达式D. 可以是任意表达式 5. 以下错误的if语句是()。 A. if(x>y)z=x; B. if(x==y)z=0; C. if(x!=y)printf("%d", x)elseprintf("%d", y); D. if(x<y){x++;y;} 6. 已知int x=10, y=20, z=30;,语句if(x>y) z=x;x=y;y=z;运行后,x, y, z的值是()。 A. x=10, y=20, z=30B. x=20, y=30, z=30 C. x=20, y=30, z=10D. x=20, y=30, z=20 7. 当a=1, b=3, c=5, d=4时,运行完下面一段程序后x的值是()。 if(a<b) if(c<d)x=1; else if(a<c) if(b<d)x=2; elsex=3; elsex= 6; elsex=7; A. 1B. 2C. 3D. 6 8. 有如下程序,正确的输出结果是()。 #include <stdio> void main() {int a=15, b=21, m=0; switch(a%3) { case 0:m++;break; case 1:m++; switch(b%2) {default:m++; case 0:m++;break;} } printf("%d\n", m); } A. 1B. 2C. 3D. 4 9. 若a, b, c1, c2, x, y均是整型变量,错误的switch语句是()。 A. switch(a+b)B. switch(a*a+b*b) {{ case 1: y=a+b; break;case 3:break; case 0: y=a-b; break;case 1: y=a+b; break; case 3: y=b-a; break;} } C. switch aD. switch(a-b) {{ case c1: y=a+b; break;default: y=a*b;break; case c2: y=a-b; break;case 3: default: y=b-a;case 4: y=b-a; break; }} 10. 若希望当A的值为奇数时,表达式的值为“真”,A的值为偶数时,表达式的值为“假”,则以下不能满足要求的表达式是()。 A. A%2==1B. !(A%2==0) C. !(A%2 )D. A%2 11. 若有定义语句int a, b; double x;,则下列选项中没有错误的是()。 A. switch (x%2)B. switch ((int)x/2.0) {case 0: a++; break;{ case 0: a++; break; case 1: b++; break;case 1: b++; break; default: a++; b++; }default : a++; b++; } C. switch((int)x%2)D. switch((int)(x)%2) { case 0: a++; break;{ case 0.0: a++; break; case 1: b++; break;case 1.0: b++; break; default: a++; b++; }default : a++; b++; } 12. 以下选项中与if(a==1) a=b;else a++;语句功能不同的switch语句是()。 A. switch(a) {case 1:a=b;break; default:a++; } B. switch(a==1) {case 0:a=b;break; case 1:a++; } C. switch(a) {default:a++;break; case 1:a=b; } D. switch(a==1) {case 1:a=b;break; case 0:a++; } 13. 选项中与如下嵌套if语句等价的语句是()。 if(a<b) if(a<c)k=a; elsek=c; else if(b<c) k=b;else k=c; A. k=(a<b)?a:b; k=(b<c)?b:c; B. k=(a<b)?(b<c?a:b):(b>c)?b:c); C. k=(a<b)?(a<c?a:c):(b<c?b:c); D. k=(a<b)?a:b; k=(a<c)?a:c; 14. 以下程序的运行结果是()。 #include <stdio.h> int main() {int x=1, y=0; if(!x) y++; else if(x==0) if (x)y+=2; elsey+=3; printf("%d\n", y);} A. 3B. 2C. 1D. 0 15. 以下程序的运行结果是()。 #include <stdio.h> int main() {int x=1, y=2, z=3; if(x>1) if(y>x) putchar('A'); elseputchar('B'); else if(z<x) putchar('C'); else putchar('D');} A. AB. BC. CD. D 16. 以下叙述中正确的是()。 A. if语句只能嵌套一层 B. 改变ifelse语句的缩进格式,会改变程序的运行流程 C. 不能在else子句中再嵌套if语句 D. if子句和else子句中可以是任意的合法的C语句 17. 以下程序的运行结果是()。 #include <stdio.h> void main() {int x=1, a=0, b=0; switch(x) { case 0: b++; case 1:a++; case 2:a++; b++; } printf("a=%d, b=%d\n", a, b);} A. a=2, b=1B. a=1, b=1C. a=1, b=0D. a=2, b=2 18. 以下程序的运行结果是()。 #include <stdio.h> void main() {float x=2.0, y; if(x<0.0)y=0.0; else if(x<10.0)y=1.0/x; elsey=1.0; printf("%f\n", y);} A. 0.000000B. 0.250000C. 0.500000D. 1.000000 二、 填空题 1. C语言用()表示假,()表示真。 2. 写出下列各逻辑表达式的值。设a=3,b=4,c=5。 (1) a+b>c&&b==c() (2) a||b+c&&b-c() (3) !(a>b)&&!c||1() (4) !(x==a)&&(y==b)&&0() (5) !(a+b)+c-1&&b+c/2() 3. 以下程序的运行结果是()。 #include <stdio.h> void main() { int a=1, b=2, c=3; if(a=c)printf("%d\n", c); elseprintf("%d\n", b); } 4. 以下程序的运行结果是()。 #include <stdio.h> int main() { int ch1=0, ch2=5; if(ch1!=3) printf("ch1:%d", ch1); elseprintf("ch2:%d", ch2); } 5. 若从键盘输入58,以下程序的运行结果是()。 #include <stdio.h> int main() { int a; scanf("%d", &a); if(a>50)printf("%d", a); if(a>40)printf("%d", a); if(a>30)printf("%d", a); } 6. 以下程序的运行结果是()。 #include <stdio.h> int main() { int a=100; if(a>100)printf("%d\n", a>100); elseprintf("%d\n", a<=100); } 7. 以下程序的运行结果是()。 #include <stdio.h> int main() { int a=1, b=0; switch(a) {case 1: switch (b) {case 0: printf("**0**"); break; case 1: printf("**1**"); break;} case 2: printf("**2**"); break; } } 三、 编程题 1. 编写程序,输入一个整数,判断该数的正负性和奇偶性。 2. 从键盘输入一个字符,如果是大写字母,就转换成小写; 如果是小写字母,就转换成大写; 如果是其他字符原样保持并将结果输出。 3. 从键盘输入一个数,判断其是否是5的倍数而不是7的倍数。如果是,输出Yes,否则输出No。 4. 编写程序,输入一个整数,当其为65时输出A,66时输出B,67时输出C,其他值时输出END。