哲理
5.1 选择结构
在人生中我们会遇到各种各样的选择,有时候选择可能会决定一个人的一生。那么在程序中选择结构是什么呢?选择结构用于判断给定的条件,根据判断的结果来决定怎么执行程序,执行哪一步程序。多数情况下不同的判断结果,导致程序执行不同的过程或步骤。
在上一章图4.2 三目运算符一定程度上也就是选择结构一种普通情况,在图4.2中我们首先判断“表达式1”的运行结果是否为真,如果判断结果为真,那么我们就会执行“表达式2”,如果判断结果为假,我们就会执行“表达式3”。在程序执行的过程中,无论判断结果为真还是为假,每一次只能执行“表达式2”或者“表达式3”的其中一种,因此就产生的程序运行过程中相应结果的差异。比如,现实生活中,总有阴天和晴天,那么我们就可以把“今天下雨”做为“表达式1”,“拿伞”作为“表达式2”,“不拿伞”作为“表达式3”。所以,则有如果“今天下雨”为真(“表达式1”为真),即今天要下雨,那么我们就会很自然的选择“拿伞”(执行“表达式2”)。反之如果“今天下雨”为假(“表达式1”为假),即今天不下雨,那么我们就不会拿伞了(执行“表达式3”)。具体如图5.1所示。
如图5.1,是一个多种选择结构的流程图。我们首先进行“判断1”,如果“判断1”为真,就会执行“语句1”,否则执行“判断2”,最后执行“语句4”。如果“判断2”为真,就会执行“语句2”,然后执行“语句4”,否则执行“判断3”。如果“判断3”为真,就会执行“语句3”,然后执行“语句4”,否则直接执行“语句4”。
如图5.3所示,它是图5.2的一个实际应用,该图用于判断学生成绩等级。如果学生成绩“大于等于90”为真,那么该学生等级为“优秀”,并加一句鼓励“继续努力”,否则学生成绩小于90分。然后在判断学生的成绩是不是“大于等于80”。如果成绩“大于等于80”为真,那么该学生的等级为“良好”,并加一句鼓励“继续努力”,否则该学生的成绩小于80分。如果成绩“小于等于60”为真,那么该学生的等级为“及格”,并加一句鼓励“继续努力”,否则该学生的成绩小于60分,只能说句“继续努力”了。所以同学们要好好学习哟!!!
5.2 if语句选择结构
在C语言中实现选择结构时,最常用的是if语句和switch语句。
5.2.1 if语句的基本介绍
if语句有三种一般形式:
-
if(表达式) 语句
-
if(表达式)
语句1
else
语句2
-
if(表达式1) 语句1;
else if(表达式2) 语句2;
else if(表达式3) 语句3;
┇
else if(表达式n) 语句n;
else 语句n+1;
以上三种是最基本if语句的形式。当然还有其他多种类似形式。那么对于第一种if语句,其功能就是判断表达式是否为真,如果为真,执行“语句”。对于第二种if-else语句,如果“表达式”为真,执行“语句1”,否则为假,执行“语句2”。对于第三种if-else if-else语句存在多种可选项,如果“表达式1”为真,执行“语句1”,否则判断“表达式2”,如果“表达式2”为真,则执行“语句2”,依次进行比较。如果表达式都不为真,执行else,如果有其中的一个表达式为真,则结束对应的整个if判断语句。
比如:
-
if(age>18) printf(“你已经成年了”);
-
if(grade > =60) printf(“成绩及格\n”);
else printf(“成绩不及格\n”);
-
if(grade >=90) printf(“优秀\n”);
else if(grade >=80) printf(“良好\n”);
else if(grade >=60) printf(“及格\n”);
else printf(“继续努力\n”);
经过上面一堆理论知识的讲解,下面将会用几个实例来证实我们的理论,加深大家对if语句的理解。
【例5.1】输入一个数,判断这个数是否大于95?
解题思路:很简单,用scanf函数从键盘接受一个整数,然后用if语句把输入的数据与95进行比较。最后根据结果给出提示信息。对应上面理论知识部分中if语句的第二种形式。
编写程序:
#include <stdio.h>
int main()
{
int num;
printf("请输入一个整数:");
scanf("%d", &num);
if (num >= 95)
{
printf("%d大于等于95。\n", num);
}
else
{
printf("%d小于95。\n", num);
}
return 0;
}
第一次运行结果:
请输入一个整数:23
23小于95。
Press any key to continue
第二次运行结果:
请输入一个整数:98
98大于等于95。
Press any key to continue
程序分析:第一次运行结果我们输入23,用if语句判断23是否大于等于95,因为小于95,所以输出else里面对应的printf函数。第二次运行结果我们输入98,因为98满足if语句,所以输出if里面的printf函数。
【例5.2】比较三个数的大小,按从小到大的顺序输出。
解题思路:我们输入三个数,让这三个数两两进行比较即可。具体可以参考中学数学中数值比较大小。对应上面理论知识部分中if语句的第一种形式。
编写程序:
#include <stdio.h>
int main()
{
int first_num,second_num,third_num,tmp_num;
printf("请输入一个整数:");
scanf("%d,%d,%d", &first_num,&second_num,&third_num);
if (first_num > second_num)
{
tmp_num = first_num;
first_num = second_num;
second_num = tmp_num;
}
if (first_num > third_num)
{
tmp_num = first_num;
first_num = third_num;
third_num = tmp_num;
}
if (second_num > third_num)
{
tmp_num = second_num;
second_num = third_num;
third_num = tmp_num;
}
printf("%d < %d < %d\n", first_num, second_num, third_num);
return 0;
}
运行结果:
请输入一个整数:12,54,4
4 < 12 < 54
Press any key to continue
程序分析:程序是按照从小到大进行排序的,因为if语句是如果前一个比后一个大,那么就把后一个放到后面。经过三个if语句的使用,最终实现排序。
【例5.3】国家税法规定,工资薪金使用七级超额进制。应交个人所得税是按个人工资薪金计算交纳的个人应交的税额,以每月收入额减除免税的个人应负担的“五险一金”等项目,再减去允许扣除费用3500元(外籍人员按4800元)后的余额,为应纳税所得额。
公式:
全月应纳税额 = (工资 — 五险一金 — 3500);
个人应交所得税 = 全月应纳税额 * 税率 — 速算扣除数;
七级超额进制:
1. 全月应纳税额不超过1500元的,税率为3%,速算扣除数0;
2. 全月应纳税额超过1500元至4500元的部分,税率为10%。速算扣除数105元;
3. 全月应纳税额超过4500元至9000元的部分,税率为20%。速算扣除数555元;
4. 全月应纳税额超过9000元至35000元的部分,税率为25%,速算扣除数1005元;
5. 全月应纳税额超过35000元至55000元的部分,税率为30%,速算扣除数2755元;
6. 全月应纳税额超过55000元至80000元的部分,税率为35%。速算扣除数5505元;
7. 全月应纳税额超过80000的部分,税率为45%。速算扣除数13505元。
注:由于在实际生活中,不同地区的五险一金是不一样的。所以计算的时候暂时不考虑五险一金。
解题思路:我们根据题目中给出的数学公式即可。这部分只要求大家初中的数学知识足够。对应上面理论知识部分中if语句的第三种形式。
编写程序:
#include <stdio.h>
int main()
{
double money_before,money_after;
printf("money is ");
scanf("%lf", &money_before);
if(money_before <= 3500)
{
printf("您的工资达不到基本工资。请向国家申请基本生活保障。\n");
return -1;
}
money_after = money_before-3500;
if( money_after < 1500)
{
money_after = money_after*0.03;
}
else if( money_after < 4500)
{
money_after = money_after*0.1-105;
}
else if( money_after < 9000)
{
money_after = money_after*0.2-555;
}
else if( money_after < 35000)
{
money_after = money_after*0.25-1005;
}
else if( money_after < 55000)
{
money_after = money_after*0.3-2755;
}
else if( money_after < 80000)
{
money_after = money_after*0.35-5505;
}
else
{
money_after = money_after*0.45-13505;
}
printf("工资为:%0.01f,交税:%.01f,应得工资:%.01f\n", money_before,money_after,money_before-money_after);
return 0;
}
运行结果:
money is 9500
工资为:9500.0,交税:645.0,应得工资:8855.0
Press any key to continue
程序分析:此程序看上去代码挺多,不过也只是if-else if-else的多个使用而已,看透它,就是纸老虎。
如上我们通过多重if-else-if实现了交税问题,每一个if或者else-if对应一中收税的的标准。看上去例5.3程序的代码中if-else if-else挺多的,那么是不是我们可以把部分if-else语句放到一个if-else的其中一个子语句中呢?答案是肯定的,那么写成这个样的形式:
if()
{
if(){}else{}
}
else
{
if(){}else{}
}
我们称这样形式为if语句的嵌套。具体请看下节的详细说明。
5.2.2 多重if语句嵌套
在if语句中包含一个或多个if语句称为if语句的嵌套。if语句嵌套的基本形式如图5.4所示。
在书写时需要注意if和else配对,else总是与它最近的未配对的if配对。比如,我们把上面的语句进行适当的改变,有如图5.5形式。图5.6为其对应的流程图。
要求遵循else与最近未匹配的if进行匹配,所以有第一个else与第三个if进行匹配,就是所标记的“内层嵌套”。第二个else与最近未匹配的if进行匹配,由于第三个if已经与第一个else进行了匹配,所以第二个if与第二个else进行匹配。那么第三个else将会与第一个if进行匹配,因为后两个if已经与前两个else对应匹配了。
但是在编程中为了能够更加清楚直观地了解到每个else对应的if,通常会加上一个花括号,用于标记对应if的作用范围。
如下:
if()
{
if()
{ }
else
{}
}
else
{}
在这个if-else语句中,可以清楚地看出那个else对应那个if,这样在编程时,特别是编写较大或者较复杂的程序时,减少出现出现错误的可能性。
比如:
if(a>=60)
{
if(a>=85)
{
printf(“优秀!\n”);
}
else
{
printf(“及格!\n”);
}
}
else
{
printf(“继续努力!\n”);
}
理论讲解完成,又到了我们用实践来检验真理的时候!请看下题。
【例5.4】程序实现判断某一年是否为闰年?
解题思路:在上一章中的条件运算符与条件表达式一节中的三目运算符就曾被用来判断那一年是闰年。这个例题我们使用if语句进行闰年的判断。首先让我们再加深一下闰年判断的条件。可以4整除且不可被100整除,或者被400整除的年份都是闰年。我们首先判断年份能否被4整除,如果不能。注定该年与闰年无缘。否则判断能否被100整除。如果能这也不是闰年。如果不能,我们在判断能否被400整除,如果能那就是想要的闰年了,如果不能,呜呜,就是平年了。
编写程序:
#include <stdio.h>
int main()
{
int year, leap;
printf("输入年份:");
scanf("%d", &year);
if (year%4 == 0)
{
if (year%100 == 0)
{
if (year%400 == 0)
{
leap = 1;
}
else
{
leap = 0;
}
}
else
{
leap = 1;
}
}
else
{
leap = 0;
}
if (leap)
{
printf("%d is ", year);
}
else
{
printf("%d is not ", year);
}
printf("a leap year.\n");
return 0;
}
第一次运行结果:
输入年份:2008
2008 is a leap year.
Press any key to continue
第二次运行结果:
输入年份:2006
2006 is not a leap year.
Press any key to continue
程序分析:程序第4行,定义变量leap,实现是闰年还是平年的判断。当leap为1时,表示是闰年。leap为0,表示平年。第7~28行,就是实现判断是否是闰年的核心代码。第29~37行,实现最终结果的输出,相当于提示信息,提示你是闰年还是平年。
5.3 switch语句
5.3.1 switch语句基本介绍
在编程时,如果使用多重的if-else语句,会降低程序执行效率,并且在书写时也会显得臃肿不堪。对于一些特定的逻辑结构显得并不是那么清晰。比如等级的划分,省市的划分,工资的划分等。
switch语句的基本语法:
switch(表达式)
{
case 常量1: 语句1;
case 常量2: 语句2;
case 常量3: 语句3;
┇ ┇ ┇
case 常量n: 语句n;
default : 语句n+1;
}
如图5.7和5.8为switch语句的两种流程图。
说明:
- switch后面的“表达式”,数据类型只能是整型或者字符型。
比如:
- switch语句花括号内是一个复合体语句。复合体语句是由若干case语句开头和default语句结尾的语句组成。每个case后面都有一个常量(或者常量表达式),switch后面的“表达式”,会与每一个case后面的数据进行比较,如果相同就会执行case后面相应的语句,否则执行default后面的语句。
比如:
switch(a%5)
{
case 0:语句1;break;
case 1:语句2;break;
case 2:语句3;break;
default: 语句4;
}
假如a取6,则表达式a%5的余为1,所以执行且仅执行第二个case语句,即“case 1:语句2;break;”,但是如果没有break关键字,程序会一直执行到switch语句的结尾或者有break关键字处结束。假如a取4,则表达式a%5的余为4,和case语句不匹配,所以执行default语句。
- case语句出现的先后顺序不影响执行结果。
比如:
switch(a)
{
case ‘D’:…
case ‘B’:…
case ‘C’:…
case ‘A’:…
┇
}
- 每个case后面对应的变量(或常量)是互不相同的,如果相同就会造成歧义。
比如:
switch(a)
{
case ‘A:
case ‘B’:
case ‘A’:
}
在这个switch中,存在case后面对应的常量‘A’重复出现,这样会造成矛盾现象。
- case标号只起标记作用,执行switch语句时程序就会自动找到对应的标号,然后执行对应标号后面的语句。如果每个case语句之后对应多条语句可以不用花括号标记起来,但是建议标记,这样有利于提高程序的可读性。
- 多个case语句可以组成一条语句执行。
比如:
switch(a)
{
case 1:
case 2:
case 3:printf(“hello my girl friend!\n”);break;
case 4:
case 5:printf(“hello my boy friend!\n”);break;
}
如果a为1,程序会先执行语句“case 1”,由于没有break语句,然后执行语句“case 2”,语句“case 3”,直到遇到“case 3” 后面的break,结束整个switch语句的执行。
【例5.5】输入某年某月某日,判断这一天是这一年的第几天?
解题思路:以3月1日为例,我们应该先把前两个月(1月,2月)的加起来,然后再加上这个月已经过得天数。唯一特殊的是需要判断输入的年份是不是闰年,如果是闰年2月是29天,平年是28天。
编程程序:
#include<stdio.h>
int main()
{
int year,month,day;
int l,sum;
char c;
printf("请输入年月日(格式如2012-1-1):\n");
scanf("%d%c%d%c%d",&year,&c,&month,&c,&day);
switch(month)
{
case 1:sum=0;break;
case 2:sum=31;break;
case 3:
if((year%4==0 && year%100!=0)||(year%400==0))
sum=60;
else
sum=59;
break;
case 4:sum=90;break;
case 5:sum=120;break;
case 6:sum=151;break;
case 7:sum=181;break;
case 8:sum=212;break;
case 9:sum=243;break;
case 10:sum=273;break;
case 11:sum=304;break;
case 12:sum=334;break;
default:printf("date error!\n");
}
sum=sum+day;
printf("%d年%d月%d日是这一年的第%d天。\n", year, month, day,sum);
}
第一次运行结果:
请输入年月日(格式如2012-1-1):
2012-3-1
2012年3月1日是这一年的第61天。
Press any key to continue
第二次运行结果:
请输入年月日(格式如2012-1-1):
2013-3-1
2013年3月1日是这一年的第60天。
Press any key to continue
程序分析:程序第9~30行,为核心代码。“case 1”表示1月,“case 2”表示2月,依次类推。当输入的月份为1月时,那么这一年的天数就是输入的天数决定,就是变量day决定。“case 3”表示对2月是不是闰年的判断,如果是2月就是29天,否则28天。“default”表示输入的月份不符合要求。
5.3.2 多重switch语句的嵌套
在switch语句中,如果我们在每一个case语句后再添加一个或多个switch语句,就会构成switch的语句的嵌套。
switch语句的嵌套语法:
switch(表达式)
{
case 常量1:
[switch(表达式1)
{
case 常量11: 语句11;
case 常量12: 语句12;
┇
}]
┇
case 常量2:
[switch(表达式2)
{
case 常量21: 语句21;
case 常量22: 语句22;
┇
}]
┇
┇ ┇ ┇
case 常量n:
[switch(表达式n)
{
case 常量n1: 语句n1;
case 常量n2: 语句n2;
┇
}]
┇
default : 语句n+1;
}
如下就是switch语句的嵌套:
switch(a)
{
case 10:
switch(b)
{
case 1:…;break;
case 2:…;break;
┇
default:…
}
break;
case 20:
switch(c)
{
case 3:…;break;
case 4:…;break;
┇
default:…;
}
break;
case 30: …;break;
┇
default: …;
}
如图5.9所示为多重switch语句的嵌套流程图。
【例5.6】部分省市信息查询系统。
解题思路:此实例为一个简单的switch语句,目的就是使大家学会switch语句的使用。具体细节请看代码。
编写程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 0;
printf("*************************\n");
printf("-------部分省份选择------\n");
printf("*************************\n");
printf("*** 1. 山东省 ***\n");
printf("*** 2. 安徽省 ***\n");
printf("*** 3. 河南省 ***\n");
printf("*** 4. 山西省 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("欢迎下次使用!\n");exit(1);
case 1:
printf("*************************\n");
printf("-------部分市区选择------\n");
printf("*************************\n");
printf("*** 1. 济南市 ***\n");
printf("*** 2. 青岛市 ***\n");
printf("*** 3. 泰安市 ***\n");
printf("*** 4. 菏泽市 ***\n");
printf("*** 5. 济宁市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("欢迎下次使用!\n");exit(1);
case 1:printf("你选择的是济南市!\n");break;
case 2:printf("你选择的是青岛市!\n");break;
case 3:printf("你选择的是泰安市!\n");break;
case 4:printf("你选择的是菏泽市!\n");break;
case 5:printf("你选择的是济宁市!\n");break;
default:printf("输入的数据错误!\n");exit(1);
}
break;
case 2:
printf("*************************\n");
printf("-------部分市区选择------\n");
printf("*************************\n");
printf("*** 1. 合肥市 ***\n");
printf("*** 2. 蚌埠市 ***\n");
printf("*** 3. 芜湖市 ***\n");
printf("*** 4. 安庆市 ***\n");
printf("*** 5. 阜阳市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("欢迎下次使用!\n");exit(1);
case 1:printf("你选择的是合肥市!\n");break;
case 2:printf("你选择的是蚌埠市!\n");break;
case 3:printf("你选择的是芜湖市!\n");break;
case 4:printf("你选择的是安庆市!\n");break;
case 5:printf("你选择的是阜阳市!\n");break;
default:printf("输入的数据错误!\n");exit(1);
}
break;
case 3:
printf("*************************\n");
printf("-------部分市区选择------\n");
printf("*************************\n");
printf("*** 1. 郑州市 ***\n");
printf("*** 2. 开封市 ***\n");
printf("*** 3. 洛阳市 ***\n");
printf("*** 4. 焦作市 ***\n");
printf("*** 5. 新乡市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("欢迎下次使用!\n");exit(1);
case 1:printf("你选择的是郑州市!\n");break;
case 2:printf("你选择的是开封市!\n");break;
case 3:printf("你选择的是洛阳市!\n");break;
case 4:printf("你选择的是焦作市!\n");break;
case 5:printf("你选择的是新乡市!\n");break;
default:printf("输入的数据错误!\n");exit(1);
}
break;
case 4:
printf("*************************\n");
printf("-------部分市区选择------\n");
printf("*************************\n");
printf("*** 1. 太原市 ***\n");
printf("*** 2. 大同市 ***\n");
printf("*** 3. 阳泉市 ***\n");
printf("*** 4. 朔州市 ***\n");
printf("*** 5. 临汾市 ***\n");
printf("*** 0. 退出 ***\n");
printf("*************************\n");
printf("---->>>>");
scanf("%d", &num);
switch(num)
{
case 0:printf("欢迎下次使用!\n");exit(1);
case 1:printf("你选择的是太原市!\n");break;
case 2:printf("你选择的是大同市!\n");break;
case 3:printf("你选择的是阳泉市!\n");break;
case 4:printf("你选择的是朔州市!\n");break;
case 5:printf("你选择的是临汾市!\n");break;
default:printf("输入的数据错误!\n");exit(1);
}
break;
default:printf("输入的数据错误!\n");exit(1);
}
return 0;
}
运行结果:
*************************
-------部分省份选择------
*************************
*** 1. 山东省 ***
*** 2. 安徽省 ***
*** 3. 河南省 ***
*** 4. 山西省 ***
*** 0. 退出 ***
*************************
---->>>>1
*************************
-------部分市区选择------
*************************
*** 1. 济南市 ***
*** 2. 青岛市 ***
*** 3. 泰安市 ***
*** 4. 菏泽市 ***
*** 5. 济宁市 ***
*** 0. 退出 ***
*************************
---->>>>4
你选择的是菏泽市!
Press any key to continue
程序分析:程序中每一个外层switch语句中,就嵌套一个的switch语句。通过选择对应的选项输出对应省市结果。程序中的exit(1)表示退出程序。