第5章
分 支 结 构



学习目标
 正确地判断和使用逻辑表达式和关系表达式; 
 掌握各种形式if语句的语法和用法,注意嵌套if结构中if和else的匹配关系; 
 掌握switch语句语法和使用方法,注意switch语句的控制流程; 
 掌握switch语句中break语句的使用以及switch语句的嵌套; 
 熟练使用if结构和switch结构解决简单的应用问题。




5.1if结构
在日常生活中大家可能经常遇到这样的问题,如果今天天气好我就出去郊游,否则就在家看电视。对于这种需要根据不同情况执行不同操作的问题,计算机该如何处理?顺序语句只能按照语句的先后顺序来运行,显然不能根据判断结果
选择处理方式,这要求程序本身具有判断能力。本章介绍的分支结构正是为解决这一类问题而设定的。本章将会介绍C语言中的几种分支结构,包括if结构和switch结构。
if结构是最常见的分支结构,if语句是单分支结构,ifelse构成双分支结构,同时可以利用if语句或者ifelse语句的嵌套实现多分支结构。
5.1.1if语句
if语句是最简单的分支语句,是一种单分支结构,其语法形式为: 


图51if结构的

流程图


if(<表达式>)

{

<语句A>

}


上述结构中的<表达式>一般为条件表达式或者逻辑表达式,用一对小括号括起来。if语句的功能是先判断<表达式>的逻辑值,若该逻辑值是“真”,则进入分支运行<语句A>,否则什么也不运行。式中,<语句A>是分支语句,可以是一条语句也可以是多条语句,如果分支结构只有一条语句。则大括号可以省略。
if结构的流程图如图51所示。

【例51】若有定义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。
【例52】从键盘任意输入一个实数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.2ifelse语句
ifelse语句是由关键字if和else构成的二分支结构,其语法形式为: 

if(<表达式>)

{

<语句A>

} else

{

<语句B>

}


上述结构中的<表达式>一般为条件表达式或者逻辑表达式,用一对小括号括起来。ifelse语句的功能是先判断<表达式>的逻辑值,若该逻辑值是“真”,则运行<语句A>,否则运行<语句B>。式中,<语句A>、<语句B>都是分支语句,可以是一条语句也可以是多条语句,如果只有一条语句,则大括号可以省略。一次条件判断结束,<语句A>、<语句B>只可能运行其一,不可能同时都运行。

ifelse结构的流程图如图52所示。


图52ifelse结构流程图



【例53】从键盘输入一个整数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}

【例54】编写程序,通过输入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语句或者ifelse语句,也就是前面所述的if结构中<语句A>、<语句B>可以是if语句或者ifelse语句。if语句的嵌套层次原则上可以是任意多层,但通常情况下不建议使用层数较多的嵌套。if语句的嵌套形式一般分为两种: 规则嵌套和不规则嵌套。
1. 规则嵌套
规则嵌套是每一层的if或else分支嵌套着另一个ifelse结构。其语法形式如下: 

if(<表达式1>)

{

<语句A>

}

else if(<表达式2>)

{

<语句B>

}

else if(<表达式3>)

{

<语句C>

}

…

else if(<表达式n>)

{

<语句X>

}

else

{

<语句X+1>

}

上述结构的功能是先判断<表达式1>的逻辑值,若该逻辑值是“真”,则运行<语句A>,否则判断<表达式2>的逻辑值,若为“真”,则运行<语句B>,否则继续判断<表达式3>的逻辑值……以此类推。
规则嵌套的流程图如图53所示。


图53ifelse的规则嵌套流程图



【例55】编写程序,通过输入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条件?
【例56】从键盘输入学生百分制成绩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}

运行结果: 

在使用ifelse嵌套结构时需要注意以下几点。
(1) C语言规定,else总是与在它上面、距它最近且尚未匹配的if配对。
(2) 程序书写采用缩进方式,将同一层的分支结构对齐,这样可以增加程序的美观性和可读性。
(3) 程序设计时,ifelse结构不宜太多,2~3层左右,否则对程序的运行效率会有所影响。
2. 任意嵌套
与规则嵌套不同,任意嵌套是在ifelse结构中的任一分支中嵌入if结构或者ifelse结构。实际问题中,大部分都是任意嵌套的形式。
对于初学者来说,多重ifelse结构最容出错的就是if与else的配对问题。建议大家在编写程序时,先写好分支结构的左右大括号,再在大括号中间编写分支语句或者其他的分支结构,避免遗漏右边大括号造成的程序错误。同时建议,对于只有一条语句的分支也不要省略大括号,避免出现不必要的逻辑错误。
【例57】试比较下列两段程序的差异。
程序一: 

#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语句和ifelse语句的多重嵌套来实现。但是如果需要判断的分支很多,嵌套层次就会变得复杂,而且程序运行效率会降低。为了解决这个问题,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语句运行的流程图如图54所示。


图54switch语句流程图


【例58】输入成绩等级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语句结束。例如,在例58中,如果去掉各个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程 序 范 例

【例59】已知某公司员工的保底月薪为1500,某月所接工程的绩效profit(整数)与绩效提成的关系如下所示,计算员工的当月薪水。
工程绩效profit提成比率
profit<1000没有提成
1000<=profit<200010%
2000<=profit<500015%
5000<=profit<1000020%
profit>=1000025%
分析: 这是一个典型的多分支问题,员工最终的薪水=保底月薪+工程绩效*提成比率,可以使用ifelse的嵌套结构,也可以使用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语句,但所有的多分支都可以用嵌套ifelse语句实现。
【例510】写一程序,从键盘输入年份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语言中分支结构通过ifelse语句和switch语句实现。
ifelse语句可以实现单分支和双分支结构,使用嵌套ifelse结构可以实现多分支。
switch语句可以实现多分支结构,但不是所有的多分支都可以用switch结构实现。switch结构中要注意用好break语句。
ifelse语句和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.  改变ifelse语句的缩进格式,会改变程序的运行流程
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。