第3章〓选择结构程序设计 案例导读 技能目标: (1) 掌握结构化程序设计的3种基本结构。 (2) 掌握不同的if语句的格式,掌握其实现选择结构的方法。 (3) 掌握使用switch语句的格式及应用方法。 (4) 掌握避免使用选择结构时常见的错误,能熟练编写选择结构程序。 素质目标: (1) 学会做一个凡事有条理的人,懂得按照事情的计划和顺序来做,学会统筹管理和节约时间,提高学习和办事的效率。 (2) 通过多种选择结构的编程练习,使学生掌握选择结构的概念及多种语句的使用,培养学生将知识应用于解决实际问题的意识。 (3) 通过对易犯错误进行整理和案例分析,培养学生良好的编程习惯,树立问题意识,提升自我的灵活性,从而提升学生自主学习的能力。 3.1选择结构if语句 3.1.1if语句 if在英文中的含义是“如果”,也就意味着判断。C语言用if语句可以构成分支结构。它根据给定的条件进行判断,以决定执行某个分支程序段。if语句的一般格式如下: if(表达式)语句 图31if语句的执行流程 其中,表达式一般为逻辑表达式或关系表达式。语句可以是一条简单的语句或多条语句,当为多条语句时,需要用“{}”将这些语句括起来,构成复合语句。 if语句的执行过程: 当表达式的值为真(非0)时,执行语句,否则直接执行if语句下面的语句。if语句的执行流程如图31所示。 【例31】编程实现,输入两个整数,输出这两个数中较大的数。 #include<stdio.h> int main() { int a,b,max; /*定义整型变量a、b和max*/ printf("请输入两个整数:"); /*输出屏幕提示*/ scanf("%d%d",&a,&b); /*从键盘输入a、b的值*/ max=a; /*假设a是较大的并赋值给max*/ if(a<b) /*若a比b小,则将b赋给max*/ max=b; printf("两数中较大的数为: %d\n",max); /*输出结果*/ return 0; /*函数返回值0*/ } 运行结果: 请输入两个整数: 5 33 两数中较大的数为: 33 程序说明: 定义3个变量,分别为变量a、变量b和变量max,用来存放输入的两个整数和较大数。从键盘输入两个整数,首先假设a是较大数,将a的值赋给max,然后使用if语句进行条件判断,如果a小于b,则b为较大数,即将b的值赋给max。 (1) if后面的表达式必须用“()”括起来。 (2) if后面的表达式可以是关系表达式、逻辑表达式、算术表达式等。 (3) 表达式中一定要区分赋值运算符“=”和关系运算符“==”。例如,if(x==33)判断x的值是否等于33,而if(x=33)则是把33赋值给x,所以表达式的值为33(非0),即为真。 3.1.2ifelse语句 if语句只允许在条件为真时指定要执行的语句,而ifelse语句还可以在条件为假时指定要执行的语句。ifelse语句的一般格式如下: 图32ifelse语句的执行流程 if(表达式) 语句1 else 语句2 ifelse语句的执行过程: 当表达式为真(非0)时,执行语句1,否则执行语句2。ifelse语句的执行流程如图32所示。 (1) “语句1”和“语句2”是“内嵌语句”,它们是ifelse语句中的一部分。每个内嵌语句的末尾都应该有分号。 (2) else子句不能作为语句单独使用,它必须是if语句的一部分,与if配对使用。 (3) “语句1”和“语句2”可以是一个简单的语句,也可以是一个包括多个语句的复合语句。 (4) 内嵌语句也可以是一个if语句,这就形成了if嵌套。 【例32】儿歌“红绿灯,大眼睛,一闪一闪要看清。红灯停,绿灯行,黄灯牢记准备停。”根据输入信号灯s的值,输出车辆通行情况。 #include<stdio.h> int main() { int s; /*定义整型变量s表示交通信号灯*/ printf("请输入信号灯的值:"); /*输出屏幕提示*/ scanf("%d",&s); /*从键盘输入s的值*/ if (s==1)/*s==1表示绿灯亮*/ printf("请车辆有序通行!\n"); /*输出结果*/ else /*s输入其他值,表示红灯亮*/ printf("请及时停车!\n"); /*输出结果*/ return 0; /*函数返回值0*/ } 运行结果: 请输入信号灯的值: -3 请及时停车! 程序说明: 根据输入信号灯的值,输出车辆通行情况。使用ifelse语句进行条件判断,如果输入信号灯s的值等于1,条件成立,输出“请车辆有序通行!”。输入其他值else的条件成立,输出“请及时停车!”。 【例33】编程实现,输入两个整数,输出这两个数中较大的数(用ifelse语句实现)。 #include<stdio.h> int main() { int a,b; /*定义整型变量a、b*/ printf("请输入两个整数:"); /*输出屏幕提示*/ scanf("%d%d",&a,&b); /*从键盘输入a和b的值*/ if(a>b)/*若a大于b,则输出a*/ printf("max=%d\n",a); else /*否则输出b*/ printf("max=%d\n",b); return 0; /*函数返回值0*/ } 运行结果: 请输入两个整数: 5 33 max=33 程序说明: 使用ifelse语句进行条件判断,如果a大于b,则a为较大数,if条件成立,输出a的值; 否则b为较大数,else条件成立,输出b的值。 3.1.3ifelseif语句 编程时常常需要判定一系列的条件,一旦其中某一个条件为真就立刻停止。这种情况可以采用ifelseif语句,其一般格式如下: if(表达式1)语句1 else if(表达式2)语句2 else if(表达式3)语句3 … else if(表达式n)语句n else 语句n+1 ifelseif语句的执行过程: 依次判断表达式的值,当出现某个值为真时,则执行其对应的语句,然后跳到整个if语句之外继续执行程序。如果所有的表达式都为假,则执行最后一个else后的语句,然后继续执行后续程序。ifelseif语句的执行流程如图33所示。 图33ifelseif语句的执行流程 【例34】在例32的基础上,完善信号灯在红、绿、黄3种情况下车辆的通行情况。 #include<stdio.h> int main() { int s; /*定义整型变量s表示交通信号灯*/ printf("请输入信号灯s的值:"); /*输出屏幕提示*/ scanf("%d",&s); /*从键盘输入s的值*/ if (s==1) /*s==1表示绿灯亮*/ printf("请车辆有序通行!\n"); /*输出结果*/ else if(s==0)/*s==0表示红灯亮*/ printf("请及时停车!\n"); /*输出结果*/ else /*s输入其他值表示黄灯亮*/ printf("黄灯亮,请准备停车。\n"); /*输出结果*/ return 0; /*函数返回值*/ } 运行结果: 请输入信号灯s的值: -3 黄灯亮,请准备停车。 程序说明: 本例的功能与例32相同,都是根据输入信号灯的值,输出车辆通行情况。使用ifelseif语句进行条件判断,假设s==1表示绿灯亮,s==0表示红灯亮,其他值表示黄灯亮。当输入s的值为1时,if语句条件成立,输出“请车辆有序通行!”; 当输入s的值为0时,else if语句条件成立,输出“请及时停车!”; 当输入其他值时,输出“黄灯亮,请准备停车。” 【例35】学生成绩可分为百分制和五级制,将输入的百分制成绩score,转换为相应的五级制成绩后输出。百分制与五级制成绩的对应关系如表31所示。 表31百分制与五级制成绩的对应表 百分制五级制百分制五级制 score>100或score<0无意义70≤score<80中等 90≤score≤100优秀60≤score<70及格 80≤score<90良好0≤score<60不及格 #include<stdio.h> int main() { int score; /*定义表示成绩整型score*/ printf("请输入学生成绩:"); /*输出屏幕提示*/ scanf("%d",&score); /*从键盘输入百分制成绩*/ if(score>100||score<0) /*输入分数不合理时提示错误信息*/ printf("您输入的成绩不正确!\n"); else if(score>=90)/*这里的else表示0=<score&&score<=100*/ printf("优秀\n"); else if(score>=80)/*这里的else表示0=<score&&score<=90*/ printf("良好\n"); else if(score>=70)/*这里的else表示0=<score&&score<=80*/ printf("中等\n"); else if(score>=60)/*这里的else表示0=<score&&score<=70*/ printf("及格\n"); else /*这里的else表示0=<score&&score<=60*/ printf("不及格\n"); return 0; /*函数返回值*/ } 运行结果: 请输入学生成绩: 95 优秀 程序说明: 这是一道典型的能够使用ifelseif语句的题目,根据对一系列互斥条件的判断来选择执行哪条语句。每个else本身都隐含了一个条件,如第1个else实质上表示条件score>=0&& score<=100成立,此隐含条件与对应的if所给出的条件完全相反。在编程时要善于利用隐含条件,使程序代码清晰简洁。 3.1.4if语句的嵌套 if语句的嵌套是指在if语句中又包括一个或多个if语句。内嵌的if语句可以嵌套在if子句中,也可嵌套在else子句中。 (1) 在if子句中嵌套具有else子句if语句。 if(表达式1) if(表达式2)语句1 else 语句2 else 语句3 当表达1的值为非0时,执行内嵌的ifelse语句; 当表达式1的值为0时,执行语句3。 (2) 在if子句中嵌套不含else子句的if语句。 if(表达式1) {if(表达式2)语句1} else 语句2 用“{}”把内层if语句括起来,在语法上成为一条独立的语句,使得else与外层的if配对。 (3) 在else子句中嵌套具有else子句的if语句。 if(表达式1)语句1 else if(表达式2) 语句2 else 语句3 第2个if语句作为第1个if表达式1不成立时的执行语句。当表达式2成立时执行语句2,不成立时执行语句3。 (4) 在else子句中嵌套不含else子句的if语句。 if(表达式1)语句1 else if(表达式2)语句2 第2个if语句作为第1个if表达式1不成立时的执行语句。当表达式2成立时执行语句2,不成立时什么都不执行。 【例36】编写程序,实现输入3个整数,输出最大值。 #include<stdio.h> int main() { int a,b,c,max; /*定义变量*/ printf("请输入3个整数: \n"); /*输出提示信息*/ scanf("%d%d%d",&a,&b,&c); /*输出提示信息*/ if(a>b) /*a>b*/ if(a>c)/*a>b并且a>c,最大值为a*/ max=a; else /*a>b并且c>a,最大值为c*/ max=c; else/*a<b*/ if(b>c)/*b>a并且b>c,最大值为b*/ max=b; else /*b>a并且c>b,最大值为c*/ max=c; printf("max=%d\n",max); /*输出最大值max*/ return 0; /*函数返回值*/ } 运行结果: 请输入3个整数: 8 33 -15 max=33 程序说明: 本题可以采用if嵌套进行实现,先比较a和b的大小,如果a大于b,就将a与c进行比较,如果a也大于c,那么最大值就为a; 否则,最大值为c。如果a小于b,就将b与c进行比较,如果b大于c,那么最大值就为b; 否则,最大值为c。 3.1.5if与else的配对规则 if语句在出现嵌套形式时,初学者往往会弄错if与else的配对关系,特别是当if与else的数量不对等时。因此,必须掌握if与else的配对规则。C语言规定else与其上面最接近它,还未与其他else语句配对的if语句配对。if与else的配对规则如图34所示。 图34if与else的 配对规则 同时从书写格式上也要注意程序的层次感,优秀的程序员应该养成这种习惯,以便他人阅读和自己修改程序。注意,书写格式不能代替程序逻辑。 如果if的个数与else的个数相同,则从内层到外层一一对应; 而if与else的数量不一致时,为体现编程者的意图,可在需要时添加“{}”来强制确定配对关系,否则就不能实现编程者的真正意图。 else总是与它前面最近的且尚未与其他else配对的if配对。 3.2选择结构switch语句 3.2.1switch语句的一般格式 if语句只能实现两路分支,在两种情况中选择其一执行。虽然嵌套的if语句可以实现多路的检验,但有时不够简洁。某些程序运行中多达数个分支,用ifelse语句可以根据条件沿不同支路向下执行,但程序的层次太多,显得烦琐,在一定程度上影响了可读性。为此C语言提供了实现多路选择的另一种语句——switch语句,称为开关体语句。switch语句的一般格式如下: switch(表达式) { case 常量表达式1: 语句1; case 常量表达式2: 语句2; … case 常量表达式n: 语句n; default: 语句n+1; } switch语句的执行过程: 先计算switch后面表达式的值,与某个case后面常量表达式的值相等时,就执行此case后面的所有语句,直到遇到break语句或switch语句的结束符“}”才结束。如果case后无break语句,则不再进行判断,继续执行随后所有的case后面的语句。如果没有找到与此值相匹配的常量表达式,则执行default后的语句n+1; 若无default子句,则执行switch语句后面的其他语句。 在使用switch语句时应注意以下6点。 (1) switch后的表达式和case后的常量表达式可以是整型、字符型、枚举型,但不能是实型。 (2) 同一个switch语句中,各case后的常量表达式的值必须互不相同,否则会出现多种执行方案。 (3) case后的语句可以是一条语句,也可以是多条语句,此时多条语句不必用大括号“{}”括起来。同一个switch语句中,各case后的常量表达式的值必须互不相同,否则会出现多种执行方案。 (4) default可以省略,省略时如果没有与switch表达式相匹配的case常量,则不执行任何语句,程序转到switch语句后的下一条语句执行。 (5) 各case和default子句的先后顺序可以改变,不影响执行结果。 (6) 如果多种情况都执行相同的程序块,则对应的多个case可以执行同一语句。 3.2.2switch语句的应用 【例37】春节是我国重要的传统节日之一。春节的饮食有很多讲究,北方民谚曰: “初一饺子初二面,初三合子往家转,初四烙饼炒鸡蛋,初五初六捏面团,初七、初八炒年糕,初九初十白米饭,十一十二八宝粥,十三十四汆汤丸,正月十五元宵圆。” 编程实现,从键盘上输入1~15的数字,显示对应正月初一到正月十五要吃的美食,当输入数字不在1~15范围时,输出“年过完了,撸起袖子加油干!”。 #include<stdio.h> int main() { int date; /*定义表示初几的整型date*/ printf("今天初几啊?\n"); /*输出屏幕提示*/ scanf("%d",&date); /*从键盘输入日期*/ switch(date) /*switch语句判断*/ { case 1: printf("吃饺子\n"); break; /*date值为1时,输出语句并跳出switch*/ case 2: printf("吃面条\n"); break; /*date值为2时,输出语句并跳出switch*/ case 3: printf("吃合子\n"); break; /*date值为3时,输出语句并跳出switch*/ case 4: printf("烙饼炒鸡蛋\n"); break; /*date值为4时,输出语句并跳出switch*/ case 5: /*date值为5、6时,输出语句并跳出switch*/ case 6: printf("捏面团\n"); break; case 7: /*date值为7、8时,输出语句并跳出switch*/ case 8: printf("吃炒年糕\n"); break; case 9: /*date值为9、10时,输出语句并跳出switch*/ case 10: printf("吃白米饭\n"); break; case 11: /*date值为11、12时,输出语句并跳出switch*/ case 12: printf("吃八宝粥\n"); break; case 13: /*date值为13、14时,输出语句并跳出switch*/ case 14: printf("汆汤丸\n"); break; case 15: printf("吃元宵\n"); break; /*date值为15时,输出语句并跳出switch*/ default: printf("年过完了,撸起袖子加油干!\n"); break; /*date值为其他时,输出语句并跳出switch*/ } } 运行结果: 今天初几啊? 16 年过完了,撸起袖子加油干! 程序说明: 这是一道可以利用多分支选择语句的题目,定义整型变量date,使用switch语句判断整型变量date的值,利用case语句检验date值的不同情况; 如果date的值不是case中所检验列出的情况,则输出“年过完了,撸起袖子加油干!”。在switch语句中,“case常量表达式”只相当于一个语句标号,表达式的值和某标号相等则转向该标号执行,但不能在执行完该标号的语句后自动跳出整个switch语句,所以出现了继续执行所有后面case语句的情况。这与前面介绍的if语句是完全不同的,应特别注意。 为了避免上述情况,C语言还提供了break语句,专用于跳出switch语句,break语句只有关键字break,没有参数。此部分内容将在后面详细介绍。 【例38】“十二生肖”也称“十二属相”,是我国传统文化中使用最广、影响最深的文化现象之一。所谓十二生肖,是古人将十二地支与十二种动物相配,用于记录历史年份的一种形式。因其使用的鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪大部分都是现实中的实生动物,故称“十二生肖”。 编程实现,从键盘上输入年份,输出对应的生肖。 #include<stdio.h> int main() { int year; /*定义表示年份的整型year*/ printf("请输入年份:"); /*输出屏幕提示*/ scanf("%d",&year); /*从键盘输入年份*/ printf("公元%d年是:",year); switch((year+9)%12)/*switch语句判断*/ { case 0: printf("猪年\n"); break; /*值为0时,输出语句并跳出switch*/ case 1: printf("鼠年\n"); break; /*值为1时,输出语句并跳出switch*/ case 2: printf("牛年\n"); break; /*值为2时,输出语句并跳出switch*/ case 3: printf("虎年\n"); break; /*值为3时,输出语句并跳出switch*/ case 4: printf("兔年\n"); break; /*值为4时,输出语句并跳出switch*/ case 5: printf("龙年\n"); break; /*值为5时,输出语句并跳出switch*/ case 6: printf("蛇年\n"); break; /*值为6时,输出语句并跳出switch*/ case 7: printf("马年\n"); break; /*值为7时,输出语句并跳出switch*/ case 8: printf("羊年\n"); break; /*值为8时,输出语句并跳出switch*/ case 9: printf("猴年\n"); break; /*值为9时,输出语句并跳出switch*/ case 10: printf("鸡年\n"); break; /*值为10时,输出语句并跳出switch*/ case 11: printf("狗年\n"); break; /*值为11时,输出语句并跳出switch*/ default: printf("输入错误!\n"); break; /*其他数值,输出语句并跳出switch*/ } } 运行结果: 请输入年份: 2022 公元2022年是: 虎年 程序说明: 如果能计算出输入年份在一个生肖周期中的顺序号,那么马上就能知道这一年的生肖。现已知公元1年是鸡年,鸡在生肖中的序号是10,与公元1年相差9,因此先将年份加上9再对12取余,得到的余数就正好是这一年在生肖周期中的顺序号,余数为0时顺序号为12。 3.3常见错误分析 3.3.1误把“=”作为“等于”运算符 很多初学者习惯性地用数学上的等于号“=”用作C语言关系运算符“等于”。 【例39】错误使用“等于”运算符。 #include<stdio.h> int main() { int a; scanf("%d",&a); if(a=1)/*误把"="用作"等于"运算符*/ printf("成功!\n"); else printf("失败!\n"); return 0; } 错误分析: 这种写法在程序编译过程中没有任何报错信息,但是实际上无法实现对变量a数值的判断功能。此程序无论输入的a值是否为1,都输出“成功!”。 C语言中“==”是关系运算符,用来判断两个数是否相等,a==1是判断a的值是否为1; “=”是赋值运算符,a=1是使a的值为1,这时不管a原来是什么值,表达式的值永远为真。因此,该程序需要将if(a=1)修改为if(a==1)。 3.3.2忘记必要的逻辑运算符 在数学领域中,想要判断一个数是否为(3,6),可以直接用3<x<6进行表示。对于初学者来说,很容易将其应用到C语言的编程中。 【例310】错误使用逻辑运算符。 #include<stdio.h> int main() { int x; scanf("%d",&x); if (3<x<6)/*忘记必要的逻辑运算符*/ printf("成功!\n"); else printf("失败!\n"); return 0; } 错误分析: 该程序在编译时可以顺利通过,但是无法实现对x数值的判断功能。例如,输入x的值为7,不满足大于3小于6的条件,但是输出还是“成功!”。 C语言中,关系运算符的结合性为从左至右。3<x<6的求值顺序: 先计算3<x,得到一个逻辑值0或1,再拿这个数与6作比较,结果恒为真,失去了比较的意义。对于这种情况,应使用逻辑表达式,写成if((3<x) && (x<6))。 3.3.3用复合语句时漏掉大括号 【例311】漏掉大括号。 #include<stdio.h> int main() { int a,b,t; scanf("%d,%d",&a,&b); if(a>b)/*用复合语句时漏掉大括号*/ t=a; a=b; b=t; printf("a=%d,b=%d\n",a,b); return 0; } 错误分析: 这种写法在程序编程过程中,没有任何报错信息,但是运行结果是错误的。由于if后面没有大括号,因此,if只作用于“t=a;”这一条语句,而不管a>b是否为真,都将执行后两条语句,正确的写法应为: if(a>b) { t=a; a=b; b=t; } 3.3.4在不该加分号的地方加分号 if(表达式)后是没有分号的,如果误加了分号,在程序编译过程中,并不会报错,但是无法实现预定的目标。 【例312】if表达式后多加分号。 #include<stdio.h> int main() { int a,b,t=0; scanf("%d,%d",&a,&b); if(a==b); /*在不该加分号的地方加分号*/ t=a+b; printf("%d\n,t"); return 0; } 错误分析: 程序的本意是如果a等于b,则执行t=a+b,但由于if(a+b)后跟有分号,语句“t=a+b;”在任何情况下都执行,即当a不等于b时程序也会运行语句“t=a+b;”。这是因为if后加分号相当于if后跟了一个空语句。正确的写法应为“if(a==b) t=a+b;”。 视频讲解 3.4多分支选择结构程序设计应用实战 3.4.1实战背景 东汉班固《白虎通义》言: “华山为西岳者,华之为获也。万物生华,故曰华山。”华山之阳,黄河东流; 其阴,坐拥秦岭。险峻奇绝,冠绝五岳。华山景区向全国游客实行门票优惠政策: 对身高120cm及以下儿童实行门票免费; 对身高120~150cm的儿童实行门票半价优惠。 3.4.2实战目的 (1) 变量的定义与使用。 (2) 多分支ifelse ifelse语句的应用。 3.4.3实战内容 编写一个C语言程序,输入不同身高,计算输出需要支付的门票价格。 3.4.4实战过程 #include<stdio.h> int main () { int height,price; printf ("请输入身高(cm):"); scanf ("%d",&height); if (height>=150) price=40; else if (height>=120&&height<=150) price=20; else price=0; printf("您的身高: %dcm,您需要支付: %d元\n",height,price); return 0; } 技能实战运行结果如图35所示。 图35技能实战运行结果 3.4.5实战意义 通过实战,掌握多分支选择语句的使用方法。 大家应该有敢于突破前人的勇气和智慧,自觉克服安于现状、不思进取的思想观念,坚持用创新的理论成果武装头脑,与时俱进,开拓创新,做出自己应有的贡献。