C语言程序设计第四次作业
一:改错题
输入所给源代码并编译,提示错误信息如下:
(错误一)错误信息指向第13及17行,返回检查。
错误原因:第13行关于面积的计算式的sqrt数学函数缺少“)”,导致编译器无法将括号正确配对。
改正方法:补齐缺少的“)”。
(错误二)继续编译,再次提示错误信息,如下图:
错误原因:if语句后缺少对应的“{}”大括号,导致逻辑关系出现问题。在此,需要提醒一点,在if后若只包含一条语句,原则上大括号可以省略,但是若是涉及多条语句,就必须要加上大括号,否则会出现如本题一样的问题。
改正方法:补齐所缺“{}”。
继续编译,编译成功,点击运行,并输入所给样例“5 5 3”,运行结果如下图:
该样例输入输出正常。
(错误三)紧接着输入第二组样例“1 4 1”,输出如下图:
可以看到,结果显然不符合期望,经过分析,该组数据为不符合三角形构成条件的数据,因此返回检查选择语句的判断条件部分,即第11行。
错误原因:第11行的选择语句中,三边的判断语句应为且“&&”,而不是或"||"。
改正方法:将或“||”改为且“&&”。
改正后,再次输入样例“1 4 1”,结果如下:
符合预期,改正结束。
二:学习总结:
(1):首先是关于if以及else if,switch的区别。
在之前的总结中我笔者也提到过这两者的一些区别,即独立性以及相关性。对于if而言,每一个if都相当于一个独立的系统,即程序执行时,每次遇到if,都将执行一次判断,若程序中有多个if,相当于多个if并联,因此当使用多个if时,对于程序本身而言具有一定的风险。尤其是涉及对于取值范围的判断较多的情况。而else if相当于“否则”,并且包含在对应的if之后。if和其配对的else if实际上在一定程度上是互斥的,参照该文:
https://www.zhihu.com/question/27797637?sort=created
再者可以参照第三次作业中的总结之一:
#include<stdio.h>
int main(void)
{
int ele = 0;
double cost = 0.0;
scanf("%d",&ele);
if(ele >= 0&&ele <=50)
{
cost = 0.53 * e;
printf("cost = %.2f",cost);
}
if(ele > 50) //此处笔者将else if改为if
{
cost = 50 * 0.53 + (ele - 50) * 0.58;
printf("cost = %.2f",cost);
}
else
{
printf("Invalid Value!");
}
return 0;
}
这里就是一个典型案例,当笔者输入任意小于50的值时,伴随着对应的电费的输出,同时对应非法数据提示的语句也被输出,原因就在于if的连用。详情可以参照第三次作业的其它总结:
http://www.cnblogs.com/Reloaded/p/7719971.html
以语言叙述,就是当if满足时,该独立系统执行完毕,若if后存在与其配对的else if,也不执行。当if不满足,开始按序执行下一条else if,可以理解为否则。若else if满足,系统结束,进入下一语句。else if不满足,继续在系统内执行下一条else if,若都不满足,执行else。但else并非必需。可以理解为,某if系统内不存在满足条件的语句,该系统结束,执行之后的语句。
之后是关于switch与if else语句的区别:
switch语句在C语言中的应用实际上是非常广泛和灵活的。首先是关于switch本身,是一种多选择结构,可以根据所给的变量来进行逐步判断,再给出与条件对应的语句。虽然和if相比同为选择结构,但是区别也很明显。其一是对应数值类型不同。if的判断框中,数据类型较为广泛,几乎可以覆盖所有的类型数值,尤其是对于取值范围的判断,其便捷性和灵活性要远高与switch case,因为case后只能为常量,只能为常量,只能为常量!!!这是区别之一。
其次是执行效率问题,当选择较少时,if的执行效率要高于switch case结构,但当选择较多时,则需要使用switch case结构,其中涉及的算法问题暂不深究,附参考博文链接:
http://www.cnblogs.com/pureEve/p/6564012.html
另一区别在于其比较条件的方式不同,对于if else结构实际上应用的是比对法,即将所给值与条件所给的范围或条件进行比对,而switch case结构实际上是一种枚举机制,因此省略了许多多余的计算过程,这也就解释了多选择结构中,switch语句的效率要高于if else的原因。参考博文链接:
http://www.cnblogs.com/bluesky365/p/5631517.html
关于例证,可以给出两段此次作业中的代码段来加以区分:
首先是成绩的分档问题:实际上两种结构都可以使用,但是在不考虑技巧性的情况下,先给出if语句写出的代码段:
#include<stdio.h>
int main(void)
{
int mark = 0;
scanf("%d",&g);
if(mark >= 90)
{
printf("A");
}
else if(mark >= 80)
{
printf("B");
}
else if(mark >= 70)
{
printf("C");
}
else if(mark >= 60)
{
printf("D");
}
else
{
printf("E");
}
return 0;
}
之后是switch结构:
#include<stdio.h>
int main(void)
{
int mark = 0;
scanf("%d",&mark);
switch(mark)
{
case 100: case 99: case 98:....................... //此处省略
printf("A");
break;
case 89: case 88: case 87:.................... //此处省略
printf("B");
break;
}
return 0;
}
可以看到,若是在涉及常数较多的情况下,再用switch的枚举法显然很繁琐且不现实,若是涉及到更多的数据,穷举法显然无法实现,因此相比if else结构,这实际上也是适用范围上的不同点之一。
总结而言,if相对于else if相当于一个较大的集合,else if实际上是if的几个分支,关联性较强。而switch语句与其相比,虽同为选择结构,但差异也较多。其一是其条件的取值范围,if else在取值上更加灵活,但是对于条件的判断要求考虑的要多一些,尤其是在临界值附近,要尤为谨慎。而switch虽然在取值上较为严苛,但是当处理较少选择条件以及处理常量时,其便捷性以及简洁性又远高于if else结构,因此二者应当适当选择,可以取得最好的效果。
(2)其他总结
首先是关于字符与字符串,我认为这两者在使用时要严格加以区分,特别是在输入语句中,要区分%c 与 %s,因为%c每次只读入一个字符,因此当输入的字符大于一个字符时,多余部分会丢失,因此要多加小心。
另外一点,是要时刻注意使用字符输入输出语句时,要留意缓存区中是否有残留的字符。下面以笔者遇到的一个问题为例:
笔者本来是想制作一个能计算任意多个值的平均值的程序,当用户输入数值之后,系统会询问用户是否继续输入数值,当选择“y”(即yes)时,系统允许用户继续输入数据,若是选择“n”(即no)时,停止输入循环,并计算平均值。当制作完成后,计算部分与选择部分并没有出现问题,首先给出有问题的源代码:
#include<stdio.h>
int main(void)
{
int i = 0;
char choice;
double num = 0.0,degree = 0.0;
printf("Enter you want to compute average
");
for( ; ;)
{
printf("Enter your number
");
scanf("%lf",°ree);
num += degree;
++i;
printf("Do you want to continue? y/n
");
scanf("%c",&choice); //此处的%c前遗漏了空格
if(choice == 'n'||choice == 'N')
break;
}
printf("The average = %.2f",(double)num / i);
return 0;
}
但是当笔者多次测试后,却发现了问题。笔者依次输入“3 y 5 n”,输出如下结果:
可以看到,当笔者最后一次选择n后,虽然输出了对应的均值,但是也输出了在循环内的语句,令笔者十分费解。进过长时间的检查仍未发现问题所在,无奈之下请教了老师,最终解决了该问题。
首先是观察for循环内的(“Do you want to continue”)后的转义字符,本身并没有问题,之后再观察这一句下面的scanf语句,这里就是问题所在,因为笔者的%c前并未加空格,而上一句留下的
本身是以遗留在缓存区的,所以执行到scanf语句时,%c将
读入,循环再次进行,输出了不该出现的内容。因此想以这个例子说明,一定要时刻注意缓存区内的情况,这也是老师再三叮嘱的,希望同学们不会犯和我一样的错误。
另一个典型错误出现在笔者的第三次作业中,先给出代码:
#include <stdio.h>
int main()
{
int a, b;
scanf("%d %c", &a, &b);
printf("a = %d, b = %c
", a, b);
return 0;
}
在这个问题中,笔者的测试实际上是不完全的,笔者在此问题中以为数字相对于%c为非法数据,连续输入了两次123 123,结果如图:
实际上第二个123未被读入的原因并非是%c不读入数字,而是因为%c只读入一个字符,因此只读入了一个“1”。在此也感谢助教老师的指点。
另一点需要总结的是关于字符型变量的ASCII码的问题,一定要记住几个常用字符的ASCII码,例如‘A’,‘0’;以及字符型与char,int型的混合运算问题,混合运算时,实际上是将其ASCII码数值相加,再根据输出所指定的格式给出结果。
最后是关于1与‘1’的区别。实际上这里的‘1’可以表示任意整数,应当注意的是区分二者的区别。前者为数字型常量,后者为字符型常量,本质意义是不同的。还有字符型变量的问题。
例如“char A = 'a'”,这里的‘A’为字符型变量,它是用来保存单字符的一种变量,而‘a’就为字符型常量。还有‘a’与“a”的区别,前者为字符型变量,后者为字符串型变量,虽然只差了一个符号,但是其意义也是完全不同的,在定义时也应多加小心,希望引起注意。
二:实验总结
(1)比较大小的问题:
1)流程图如下:
2)源代码如下:
#include<stdio.h>
int main(void)
{
int num1 = 0,num2 = 0,num3 = 0,middle = 0;
scanf("%d%d%d",&num1,&num2,&num3);
if(num1 > num2)
{
middle = num1,num1= num2,num2 = middle;
}
if(num1 > num3)
{
middle = num1,num1 = num3,num3 = middle;
}
if(num2 > num3)
{
middle = num2,num2 = num3,num3 = middle;
}
printf("%d->%d->%d",num1,num2,num3);
return 0;
}
3)实验分析:
本题主要应用数值交换,以及简单的if语句连用。
这道题实际上十分的经典,从顺序结构的数值交换延伸到现在的比较大小,虽然难度较低。但是笔者同样遇到了许多错误。
错误一:
笔者一开始将数值交换写入,开始运行,输入样例数据“4 2 8”,发现输出结果如下:
显然不符合逻辑。
错误原因:在数值交换语句的第二条即num1与num3的比较中,顺序与逻辑出现问题。如图:
改正方法:将出现问题的语句修改,将逻辑捋顺。
错误二:修改完成后,继续输入“4 2 8”,结果如下:
发现输出结果是由大到小的,显然不符合题意。
错误原因:分析题意出现问题。
改正方法:将输出语句的变量的顺序更换。
4)提交列表:
(2)超速处罚问题:
1)流程图如下:
2)源代码如下:
#include<stdio.h>
int main(void)
{
double exceed = 0.0,speed = 0.0,limit = 0.0,ratio = 0.0;
scanf("%d%d",&speed,&limit);
exceed = (speed - limit) / limit;
ratio = exceed * 100;
if(exceed < 0.1)
{
printf("OK");
}
else if(exceed < 0.5)
{
printf("Exceed %.0f%%. Ticket 200",ratio);
}
else
{
printf("Exceed %.0f%%. License Revoked",ratio);
}
return 0;
}
3)实验分析:
问题一:
笔者一开始编译完成后,输入了几组数据,均未出现问题。但是当笔者输入临界值“150 100”时,却出现了以下结果:
显然不符合题设要求。
错误原因:笔者在临界条件判断时,误将等号加入判断中,如图:
因而导致出现错误。
改正方法:
将等号去除。
小总结:
当出现浮点数的比较时,尽量不要取等,因为浮点数本身就具有一定的误差,可能会影响判断。因此要多加注意。
4)提交列表:
(3)加油问题:
1)流程图如下:
2)源代码如下:
#include<stdio.h>
int main(void)
{
int litre,model,choice;
double cost;
scanf("%d%d %c",&litre,&model,&choice);
switch(model)
{
case 90:
cost = 6.95 * litre;
break;
case 93:
cost = 7.44 * litre;
break;
default:
cost = 7.93 * litre;
break;
}
if(choice == 'm')
{
cost *=0.95;
}
else
{
cost *=0.97;
}
printf("%.2f",cost);
return 0;
}
3)实验分析:
本题主要使用switch结构以及if else选择语句。
错误一:笔者开始将“40 97 m”样例输入,未发现问题,但是提交时却提示部分正确,于是返回测试其它数据,输入“40 97 e”,结果如下:
发现与“40 97 e”相同。
错误原因:
在最后判断用户的输入服务种类的区域,笔者误将协助所对应的折扣也输入为9.5折,导致数据出现错误。
改正方法:将“e”对应的折扣改为0.97,即“cost *= 0.97”.
在制作流程图时,也出现了一些意想不到的错误。
错误二:
笔者开始写完流程图,输入样例数据“40 97 m”,但是出现如下提示信息:
错误原因:在判断选择是自助还是协助时,流程图内的判断框中的“choice==“m””被笔者遗漏了引号。
改正方法:
补全所缺引号。
错误三:
继续执行,样例数据不变,但是又出现了如下错误:
错误原因:
在reptor中,字符型变量应用“”“”(双引号)扩起,而不是C语言中的“‘’”(单引号)。
改正方法:
将““””(双引号)改为“‘’”(单引号)。
4)提交列表:
(4)12-24小时制转换:
1)流程图:
2)源代码:
#include<stdio.h>
int main(void)
{
int hour = 0,minute = 0;
scanf("%d:%d",&hour,&minute);
if(hour > 12)
{
hour = hour -12;
printf("%d:%d PM",hour,minute);
}
else if(hour < 12 || hour == 0)
{
printf("%d:%d AM",hour,minute);
}
else
printf("%d:%d PM",hour,minute);
return 0;
}
3)实验分析:
本题主要使用if else语句的选择结构。以及字符型变量的输入输出。
错误一:笔者在开始时,输入样例数据“21:11”,并未出现问题,但是提交后提示部分正确,于是返回检查。开始逐条检查临界条件“0:00”,结果如下:
不符合题意。
错误原因:
对于零点的临界判断不完全,导致输出了错误的结果。
改正方法:将零点单独写入else if判断语句中。用以增强稳定性。
4)提交列表:
四:博客互评链接:
1:许天笑:
http://www.cnblogs.com/snxtx/p/7763856.html
2:胡展业:
http://www.cnblogs.com/SYDneyHZY/p/7774739.html
3:郭展旭: