第3 章选择结构及其应用 在现实生活中,人们经常需要根据不同的条件做出选择,而在计算机程序设计过程 中,也可通过某一个或若干条件的判断,有选择地执行特定语句,这就是选择结构。选择 结构是一种使程序具有判断能力的程序结构。 本章主要介绍在C语言中实现选择结构的程序设计方法,选择结构主要通过if语句 或switch语句来实现。 学习目标: . 了解关系运算符和关系表达式。 . 了解逻辑运算符和逻辑表达式。 . 掌握if单分支语句、if-else双分支语句和嵌套的if语句的使用。 . 掌握switch语句的使用。 . 区分两种if语句与switch语句。 . 学会利用选择结构解决一般应用问题。 3.1 关系运算符和关系表达式 3.1.1 关系运算符 在程序中经常需要比较两个量的大小关系,以决定程序下一步的工作。比较两个量 的运算符称为关系运算符,所谓关系运算,实际上就是比较运算,即将两个操作数进行比 较并产生运算结果0(假)或1(真)。C语言提供的关系运算符有6种,如表3.1所示。 表3.1 关系运算符 运 算 符功 能 < 小于 <= 小于或等于 > 大于 >= 大于或等于 == 等于 != 不等于 C 语言程序设计 说明: (1)C语言中的小于或等于、大于或等于、等于、不等于运算符(<=、>=、==、! =)的表示与数学中的表示(≤、≥、=、≠)不同。 (2)在以上6种关系运算符中,前4种(<、<=、>、>=)的优先级相同,后两种(= =、! =)的优先级相同,前4种的优先级高于后两种。例如,a>=b! = b<=3等价于 (a>=b)! =(b<=3)。 (3)关系运算符的结合性为从左到右。 (4)C语言中“==”是关系运算符,用来判断两个数是否相等,请读者注意与赋值运 算符“=”的区别,例如,x==3用于判断x的值是否为3,x=3是使x的值为3。 3.1.2 关系表达式 关系表达式是指用关系运算符将两个数(或表达式)连接起来进行关系运算的式子。 例如,以下均是合法的关系表达式。 3<2 , a>b , ab==a , a=b>c 关系表达式的结果是逻辑值,即真值或假值,其中真值为1,假值为0,真值表示指定 的关系成立,假值则表示指定的关系不正确。例如,若a=1,b=2,c=3,则: . 关系表达式“cb”的结果为假值,因为a=1,b=2,1小于2,所以该关系不成立。 . 关系表达式“ab==a”的结果为真值,因为b=2,c=3,3大于2,所以关系式c> b成立,结果为真值,真值为1,等于a的值,所以表达式c>b==a的值为1。 . 关系表达式“a=b>c”的结果为假值,因为b=2,c=3,2小于3,所以关系式b>c 不成立,结果为假值,假值为0,所以赋值后a的值为0。注意:“>”运算符比赋值 运算符“=”的优先级要高。 3.1.3 优先级和结合性 关系运算符的结合性都是自左向右的。使用关系运算符时常常会判断两个表达式的 关系,但是由于运算符存在着优先级的问题,因此如果处理不小心就会出现错误。如进行 这样的判断操作:先对一个变量进行赋值,然后判断这个赋值的变量是否等于一个常数, 表达式如下: Number=Num==10 因为“==”运算符比“=”的优先级要高,所以Num==10的判断操作会在赋值之 前进行,变量Number得到的就是关系表达式的真值或者假值,这样并不会按照之前的意 愿执行。所以要用到括号运算符,其优先级具有最高性,因此可以使用括号来表示要优先 68 第3 章 选择结构及其应用 计算的表达式,例如: (Number=Num)==10 这种写法比较清楚,不会产生混淆,没有人会对代码的含义产生误解。由于这种写法 格式比较精确简洁,因此建议使用这种方式。 3.2 逻辑运算符和逻辑表达式 C语言中,对参与逻辑运算的所有数值,都转换为逻辑“真”或逻辑“假”后才参与逻辑 运算,如果参与逻辑运算的数值为0,则把它作为逻辑“假”处理,而所有非0的数值都作 为逻辑“真”处理。 3.2.1 逻辑运算符 有的时候,要求一些关系同时成立,而有的时候,可能只要求其中的某一个关系成立 就可以,这时,需要用到逻辑运算符。C语言中有3种逻辑运算符:逻辑与(&&)、逻辑 或(||)、逻辑非(!)。 逻辑运算符及其对应的功能说明如表3.2所示。 表3.2 逻辑运算符 运算符功 能 && 逻辑与,双目运算符,左右两个数都为“真”时才为“真”,否则为“假” || 逻辑或,双目运算符,左右两个数都为“假”时才为“假”,否则为“真” ! 逻辑非,单目运算符,改变当前数的值,“真”变“假”,“假”变“真” 逻辑运算的真值表如表3.3所示。 表3.3 逻辑运算真值表 a b a&&b a||b !a !b 真真真真假假 真假假真假真 假真假真真假 假假假假真真 3.2.2 逻辑表达式 逻辑表达式是由逻辑运算符将逻辑量连接起来构成的式子。逻辑运算符两侧的运算 69 C 语言程序设计 对象可以是任何类型的数据,但运算结果一定是整型值,并且只有两个值:1和0,分别表 示“真”和“假”。例如: (1)若a=2,则逻辑表达式! a的值为0,因为a的值为非0,逻辑值为“真”,对它进行 “逻辑非”运算,得“假”,“假”以0代表。 (2)若a=2,b=3,则逻辑表达式a&&b的值为1,因为a和b均非0,逻辑值为 “真”,所以进行“逻辑与”运算的值也为“真”,“真”以1代表。 (3)若a=2,b=3,则逻辑表达式a||b的值为1,因为a和b均非0,逻辑值为“真”, 所以进行“逻辑或”运算的值也为“真”,“真”以1代表。 (4)若a=2,b=3,则逻辑表达式! a||b的值为1,因为虽然! a的值为0,但是b非 0,逻辑值为“真”,所以进行“逻辑或”运算的值也为“真”,“真”以1代表。 说明: (1)对于a&&b,只有a为真(非0)时,才需要判断b的值,如果a为假,就不必判断 b的值。也就是说,对于&& 运算符,只有a≠0,才继续进行其右面的运算。 (2)对于a||b,只要a为真(非0),就不必判断b的值,只有a为假时,才判断b的值。 也就是说,对于||运算符,只有a=0,才继续进行其右面的运算。 (3)2 int main() { int num1,num2; //声明变量 num1=10; //给变量num1 赋值10 num2=0; //给变量num2 赋值0 printf("1 is true,0 is false\n"); //显示提示信息 //显示逻辑与表达式的结果 printf("5 int main() { int num; //定义整型变量num printf("Please enter num:"); //输出屏幕提示语 scanf("%d",&num); //从键盘输入num 的值 if(num%3==0) //判断num 是否为3 的整数倍 printf("OK!\n"); //是则输出提示信息OK! return 0; } 【运行结果】 程序运行结果如图3.4所示。 图3.4 例3-2程序运行结果 72 第3 章 选择结构及其应用 【代码解析】 (1)本示例中num 为整型。 (2)使用输入函数scanf实现给num 赋值。 (3)使用if语句进行条件判断,因为90是3的倍数,所以屏幕输出“OK!”,当输入的 整数不是3的倍数时,程序无输出。 【例3-3】 从键盘输入两个整数,输出这两个数中较大的数。 【问题分析】 根据题意,本题要实现的功能是比较两个整数的大小,这两个整数由用户从键盘输 入,然后将其中较大的数输出显示。 解决该问题的算法流程图如图3.5所示。 图3.5 例3-3的流程图 【程序代码】 #include int main() { int a,b,max; //定义整型变量a、b、max printf("Please enter two integers:"); //输出屏幕提示语 scanf("%d%d",&a,&b); //输入a、b 的值 max=a; //假设a 是较大的数,并赋值给max if(a=1&&a<=10) printf("x=%d,y=%d",x,3*x-1); if(1) printf("OK!"); //条件永远为真 if(!a) printf("input error!"); (3)在表达式中一定要区分赋值运算符“=”和关系运算符“==”。例如: y=10; if(x==3) y=2*x; 当x值为3,表达式x==3的值为真,执行语句y=2*x,则y=6;当x取其他值时, 表达式x==3的值为假,不执行语句y=2*x,则y=10。再如: y=10; if (x=3) y=2*x; 不管x原来取值多少,执行完if语句后,x值为3,为非0值,则条件永远为真,执行语 句y=2*x,则y=6。 3.3.2 if-else分支 if分支语句只允许在条件为真时指定要执行的语句,而if-else分支还可在条件为假 时指定要执行的语句。if-else分支语句的一般形式如下: if(表达式) 语句1; 74 第3 章 选择结构及其应用 else 语句2; if-else分支语句的执行过程是:当表达式为真(非0)时,执行语句1,否则执行语句 2,其执行流程图如图3.7所示。 图3.7 if-else分支的流程图 【例3-4】 编程计算下列分段函数的值并输出。 y = 2x -1 x <0 x x ≥0 { 【问题分析】 本题使用if-else语句判断用户输入的数值,若输入x的值小于0表示条件为真, y=2x-1;若输入x的值大于等于0表示条件为假,y=x;最后输出y的值。 解决该问题的算法流程图如图3.8所示。 图3.8 例3-4的流程图 【程序代码】 #include int main() { int x,y; //定义整型变量x、y 75 C 语言程序设计 printf("Please enter x:"); //输出屏幕提示语 scanf("%d",&x); // 输入x 的值 if(x<0) //使用if 语句进行判断 y=2*x-1; //如果x<0 的值为真,则y=2x-1 else y=x; //如果x<0 的值为假,则y=x printf("y=%d\n",y); //输出y 的值 return 0; } 【运行结果】 程序运行结果如图3.9所示。 图3.9 例3-4程序运行结果 【代码解析】 (1)本示例中x、y均为整型。 (2)使用输入函数scanf获得任意值并赋给x。 (3)使用if语句进行条件判断,如果x小于0,则y=2x-1,否则y=x。 (4)使用输出函数printf输出y的值。 【例3-5】 从键盘输入两个整数,输出这两个数中较大的数。 【问题分析】 本示例实现的功能与例3-3相同,都是求两个数中较大的数,不同之处在于本例使用 if-else分支来实现。 解决该问题的算法流程图如图3.10所示。 图3.10 例3-5的流程图 76 第3 章 选择结构及其应用 【程序代码】 #include int main() { int a,b,max; //定义整型变量a、b、max printf("Please enter a and b:"); //输出屏幕提示语 scanf("%d,%d",&a,&b); //输入a、b 的值 if(a #include //引用头文件,math.h 中定义了各种数学函数 int main() { double a,b,c,s,area; //定义5 个双精度浮点型变量 printf("Please enter a,b,c:"); //输出屏幕提示语 scanf("%lf%lf%lf",&a,&b,&c); //输入三条边的值 //判断3 条边均大于0,并且任意两边之和大于第3 边 if(a>0&&b>0&&c>0&&a+b>c&&a+c>b&&b+c>a) { s=(a+b+c)/2; area=sqrt(s*(s-a)*(s-b)*(s-c)); //计算面积 printf("area=%lf\n",area); //输出面积 } else //如果两边之和小于第3 边或有的边的值小于0,输出错误提示 printf("Error input!\n"); return 0; } 【运行结果】 程序运行结果如图3.13所示。 图3.13 例3-6程序运行结果 78 第3 章 选择结构及其应用 【代码解析】 (1)程序中用户输入三个数,然后对三个数进行判断,解题的关键是条件表达式的建 立。假设输入的三个数为a、b、c,根据题目要求三个数值均大于0,即a>0,b>0,c>0, 并且任意两个数值的和大于第三个数,即a+b>c,b+c>a,c+a>b。 (2)当需要表达多个条件同时满足的时候,这些子条件间以“&&”运算符连接,本示 例中的6个小条件同时满足才能保证a、b、c能构成一个三角形。 (3)本示例中else分支不能省略,如果省略了这一分支,则在不能构成三角形时,不 计算也不输出,此时程序没有任何输出结果。 3.3.3 嵌套的if语句 简单的if语句只能通过给定条件的判断决定执行给出的两种操作之一,而不能从多 种操作中进行选择,此时可通过if语句的嵌套来解决多分支选择问题。if语句中又包含 一个或多个if语句时,称为if语句的嵌套。常用的if语句嵌套有以下两种形式。 (1)形式一: if(表达式1) if(表达式2) 语句1; else 语句2; else if(表达式3) 语句3; else 语句4; 此种结构的流程图如图3.14所示。 图3.14 嵌套的if语句的流程图 在上述格式中,if与else既可成对出现,也可不成对出现,且else总是与最近的if相 配对。在编写这种语句时,每个else应与对应的if对齐,形成锯齿形状,这样就能更清晰 79 C 语言程序设计 地表示if语句的逻辑关系。例如: if(x>=0) if(x>0) y=1; else y=0; else y=-1; (2)形式二: if(表达式1) 语句1; else if(表达式2) 语句2; else if(表达式3) 语句3; …… else if(表达式n) 语句n; else 语句n+1; 此结构的程序流程是在多个分支中,仅执行表达式为真的那个else-if后面的语句。若 所有表达式的值都为0,则执行最后一个else后的语句。这种结构的流程图如图3.15所示。 图3.15 多分支if-elseif-else的流程图 80 第3 章 选择结构及其应用 【例3-7】 学生成绩可分为百分制和五分制,根据输入的百分制成绩score,转换成相 应的五分制输出,百分制与五分制的对应关系如表3.4所示。 表3.4 百分制与五分制的对应关系 百 分 制五 分 制 90≤score≤100 A 80≤score<90 B 70≤score<80 C 60≤score<70 D 0≤score<60 E 【问题分析】 本示例中,使用第二种形式的if嵌套语句对输入的数据逐步进行判断,并选择执行 相应的操作。 解决该问题的算法流程图如图3.16所示。 图3.16 例3-7的流程图 【程序代码】 #include int main() 81 C 语言程序设计 { int score; //定义变量表示分数 printf("Please enter score:"); //输出屏幕提示语 scanf("%d",&score); //输入百分制的分数 if(score>100||score<0) //分值不合理时显示出错信息 printf("Input error!\n"); else if(score>=90) //分数范围在90~100 的情况 printf("A\n"); else if(score>=80) //分数范围在80~89 的情况 printf("B\n"); else if(score>=70) //分数范围在70~79 的情况 printf("C\n"); else if(score>=60) //分数范围在60~69 的情况 printf("D\n"); else //分数范围低于60 的情况 printf("E\n"); return 0; } 【运行结果】 程序运行结果如图3.17所示。 图3.17 例3-7程序运行结果 【代码解析】 (1)本示例定义一个变量score用来表示分数,使用嵌套的if语句对分数的范围进行 检查判断,根据表3.4的对应关系,输出相应的分数等级。 (2)if和else的配对关系,else总是与其前方最靠近的、并且没有其他else与其配对 的if相配对。 (3)每一个else本身都隐含了一个条件,如本示例中的第一个else实质上表示条件 score>=0&&score<=100成立,此隐含条件与对应的if所给出的条件完全相反,在编 程时要善于利用隐含条件,使程序代码清晰简洁。 3.4 switch 语句 上面介绍的if语句,常用于两种情况的选择结构,如果要表示两种以上的条件选择, 可以采用嵌套if语句或多级嵌套的if-else语句,还可以用简洁的多分支选择switch语 82 第3 章 选择结构及其应用 句。switch语句的一般形式如下: switch(表达式) { case 常量表达式1: [语句系列1;] case 常量表达式2: [语句系列2;] …… case 常量表达式n: [语句系列n;] [default: 语句系列n+1;] } 其中,方括号中的内容是可选项。 switch语句一般形式的流程图如图3.18所示。 图3.18 switch语句一般形式的流程图 switch语句的执行过程是:首先计算switch后表达式的值,然后将其结果值与case 后的常量表达式的值依次进行比较,若此值与某case后常量表达式的值一致,即转去执 行该case后的语句系列;若没有找到与之匹配的常量表达式,则执行default后的语句 系列。 【例3-8】 从键盘上输入1~7的数字时,然后显示对应的星期几的英文单词。当输 入数字不在1~7时,输出“Error!”。 83 C 语言程序设计 【问题分析】 本示例中,要求根据输入的数字,输出星期几的英文单词,可以使用switch语句来判 断输入的数字。 解决该问题的算法流程图如图3.19所示。 图3.19 例3-8的流程图 【程序代码】 #include int main() { int a; //定义整型变量a 表示输入的数字 printf("Please enter an integer:"); //输出屏幕提示语 scanf("%d",&a); //输入1~7 的数字 switch(a) //switch 语句判断 { case 1: //a 的值为1 的情况 84 第3 章 选择结构及其应用 printf("Monday\n"); //输出Monday break; //跳出switch 语句 case 2: //a 的值为2 的情况 printf("Tuesday\n"); //输出Tuesday break; //跳出switch 语句 case 3: //a 的值为3 的情况 printf("Wednesday\n"); //输出Wednesday break; //跳出switch 语句 case 4: //a 的值为4 的情况 printf("Thursday\n"); //输出Thursday break; //跳出switch 语句 case 5: //a 的值为5 的情况 printf("Friday\n"); //输出Friday break; //跳出switch 语句 case 6: //a 的值为6 的情况 printf("Saturday\n"); //输出Saturday break; //跳出switch 语句 case 7: //a 的值为7 的情况 printf("Sunday\n"); //输出Sunday break; //跳出switch 语句 default: //默认情况 printf("Error!\n"); //提示错误 break; //跳出 } return 0; } 【运行结果】 程序运行结果如图3.20所示。 图3.20 例3-8程序运行结果 【代码解析】 本示例中使用switch来判断整型变量a的值,利用case语句检验a值的不同情况。 假设a的值为2,那么执行case为2时的情况,执行后跳出switch语句。如果a的值不是 case中所列出的情况,那么执行default后的语句。在每一个case语句或default语句后 都有一个break语句,该break语句用来跳出switch结构,不再继续执行该case语句或 default语句后的代码。 在使用switch语句时,应注意以下几点: 85 C 语言程序设计 (1)switch后的表达式和case后的常量表达式可以是整型、字符型、枚举型,但不能 是实型。 (2)在同一个switch语句中,每个case后的常量表达式的值必须互不相等。 (3)case后的语句系列可以是一条语句,也可以是多条语句,此时多条语句也不必用 大括号括起来。 (4)default可以省略,此时如果没有与switch表达式相匹配的case常量,则不执行 任何语句,程序转到switch语句后的下一条语句执行。 (5)break语句和switch最外层的右大括号是退出switch选择结构的出口,遇到第 一个break即终止执行switch语句。如果程序没有break语句,则在执行完某个case后 图3.21 例3-8不添加break 程序运行结果 的语句系列后,将继续执行下一个case中的语句 系列,直到遇到switch语句的右大括号为止。因 此,通常在每个case 语句执行完后,增加一个 break语句来达到终止switch语句执行的目的。 在例3-8中,若每个case语句中没有break语 句,则输入“5”时,输出结果如图3.21所示。 (6)每个case及default的次序是任意的,也 就是说,default可以位于case之前。例如: int a=4; switch(a) { case 1:a++; default:a++; case 2:a++; }p rintf("a=%d",a); 此程序段的运行结果为:a=6。 由此可以看出,在上述情况下,执行完default后的语句系列之后,程序将自动转移到 下一个case继续执行。 (7)如果多种情况都执行相同的程序块,则对应的多个case可以执行同一语句系列。 【例3-9】 例3-7可以用if嵌套语句实现,也可以用switch语句实现,实现代码如下。 #include int main() { int score; //定义整型变量表示分数 printf("Please enter score:"); //输出屏幕提示语 scanf("%d",&score); //输入百分制的分数 switch(score/10) //使用switch 语句判断分数的十位数 { case 10: 86