ACM程序设计第二讲-ACM常见错误湖南工学院张新玉zhangxinyu247@163.com1/1/2020223个经典错误......1/1/20203以1089A+B为例SampleInput151020SampleOutput6301/1/20204菜鸟之伤(1)#includestdio.hvoidmain(){inta,b;scanf(“%d%d”,&a,&b);printf(“%d\n”,a+b);}1/1/20205菜鸟之伤(1)总结:程序不能处理多组数据的问题是最常见的入门问题,只要掌握几种常见的类型,就可以轻松掌握了,具体处理方法曾在第一次课件有详细描述,这里省略了~1/1/20206菜鸟之伤(2)#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)!=0)printf(“%d\n”,a+b);}1/1/20207菜鸟之伤(2)总结:文件结束符EOF的值是-1而不是0,所以while(scanf(…)!=0)常常会因为死循环而造成TLE,这个必须牢记。说明:不仅仅菜鸟,很多老鸟也常常因为不注意这点而犯错误,而且还常常因为想不到会犯这种低级错误而想不到原因。1/1/20208菜鸟之伤(3)#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)!=EOF);printf(“%d\n”,a+b);}1/1/20209菜鸟之伤(3)总结:while或者for循环的条件外面误加了分号,编译不影响,但是结果循环体没有真正得到多次执行;说明:菜鸟常犯的错误,往往因为编译能通过而不能迅速察觉,尤其比赛中~提醒:当你将scanf();语句加上while循环以处理多组数据问题的时候尤其注意——因为之前有分号,很容易忘记去掉!1/1/202010菜鸟之伤(4)#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)=2)printf(“%d\n”,a+b);}1/1/202011菜鸟之伤(4)总结:C语言中,赋值符号=和判断是否相等的逻辑符号==具有完全不同的含义,往往因为我们的习惯问题,在编程中误将判断是否相等的逻辑符号写成赋值符号=。同样的,这种失误也会因为不影响编译而影响查错的时间。说明:菜鸟常犯的错误,但是有过几次教训就会牢记了,呵呵~1/1/202012以1001SumProblem为例SampleInput1100SampleOutput150501/1/202013菜鸟之伤(5)#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1){for(i=1;i=n;i++)s+=i;printf(“%d\n\n”,s);}}1/1/202014菜鸟之伤(5)总结:忘记变量的初始化是典型的菜鸟问题,不必紧张,多经历几次就牢记了~说明:普通变量的初始化还比较容易查找,而用来保存计算结果的数组的初始化更是容易忘记!1/1/202015菜鸟之伤(6)#includestdio.hvoidmain(){inti,n,s=0;while(scanf(“%d”,&n)==1){for(i=1;i=n;i++)s+=i;printf(“%d\n\n”,s);}}1/1/202016菜鸟之伤(6)总结:变量初始化放在循环外,是一个典型的ACM初级错误,因为ACM赛题的多组测试特性,如果不能在循环内初始化,将只能确保第一组数据没问题,而很多入门者习惯只测试一组数据,很容易忽略这个问题。说明:菜鸟常犯的错误,关键是要理解为什么这样会有问题,真正理解后,修改也就不难了。1/1/202017菜鸟之伤(7)#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1){s=n*(n+1)/2;printf(“%d\n\n”,s);}}1/1/202018菜鸟之伤(7)总结:数组越界还能在提交后收到RuntimeError的信息反馈,而运算中的数据溢出则往往只能收到WrongAnswer的错误提示,所以这种错误往往容易被误导成算法问题;说明:不仅菜鸟,就是大牛甚至大神,也常常犯这种错误,只是情况复杂些而已~1/1/202019菜鸟之伤(8)#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1){s=n/2*(n+1);printf(“%d\n\n”,s);}}1/1/202020菜鸟之伤(8)总结:当两个整数进行运算的时候,运算结果一定还是整数,所以不要因为常规数学惯性思维的影响而认为结果可能为浮点数;而不同数据类型一同运算的时候,运算结果的数据类型和相对复杂的类型一致(比如整数+实数,结果类型是实数)1/1/202021菜鸟之伤(9)#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1)if(n%2==0)s=n/2*(n+1);elses=(n+1)/2*n;printf(“%d\n\n”,s);}1/1/202022菜鸟之伤(9)总结:写for或者while等任何循环语句的时候,不管循环体内有几个语句,务必养成都加上一对大括号的好习惯。常常碰到的情况是这样的——本来循环体内只有一条语句,确实不用大括号,但是在修改程序的过程中,循环体内增加了其他语句,而这时却忘记了添加大括号!所以说——好习惯很重要!1/1/202023菜鸟之伤(10)#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1){if(n%2==0)s=n/2*(n+1);elses=(n+1)/2*n;}printf(“%d\n\n”,s);}1/1/202024菜鸟之伤(10)总结:这也是一个经典错误,虽然为循环体加了大括号,但是并没有包含全部的信息,造成的后果是只有一次输出——尽管对于每组数据都处理了,但是只输出最后一组结果。由于很多同学习惯每次只测试一组数据,就更容易忽略这个错误了...再次证明——好习惯很重要!1/1/202025菜鸟之伤(11)假设不会中间溢出,下面的程序是否有问题?#includestdio.hvoidmain(){inti,n,s;while(scanf(“%d”,&n)==1){s=n(n+1)/2;printf(“%d\n\n”,s);}}1/1/202026菜鸟之伤(11)总结:这也是受数学习惯影响而可能出现的一个错误,当然,这个错误很好检查,因为编译不能通过的~总结出这个只是因为确实会出现这个情况,而对于极度没有编程经验的同学来说,有时候也会带来困扰~1/1/202027还是以A+B为例题目描述:计算A+B的值,输入数据每行包含2个正整数,如果输入数据是两个负数,则结束输入。SampleInput15-1-1SampleOutput61/1/202028菜鸟之伤(12)#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)==2){if(a==-1&b==-1)return;printf(“%d\n”,a+b);}1/1/202029菜鸟之伤(12)总结:正如判断相等要用“==”一样,C语言中进行逻辑与的运算也是需要两个字符“&&”,类似的逻辑或运算也是两个字符“||”,如果是单个的字符,含义就完全不同了~1/1/202030菜鸟之伤(13)上一个程序的改进版:#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)==2){if(a==-1&&b==-1)return;printf(“%d\n”,a+b);}1/1/202031菜鸟之伤(13)总结:题目描述是负数结束输入,SampleInput最后给出的是-1,如果读题不仔细,很容易陷入思维定势,而会不加思索在程序中用-1判断,这样就真的会发生不幸的事件——尽管我也认为这个陷阱有点阴,而且未必有很大意义,但是题目并没错,而你确实读题不仔细~说明:算是经典的小陷阱,现在很少出现了1/1/202032继续以A+B为例题目描述:给定2个整数A和B,如果A+B0,请输出”OK!”,否则请输出”No~”SampleInput151-5SampleOutputOK!No~1/1/202033菜鸟之伤(14)#includestdio.hvoidmain(){inta,b;while(scanf(“%d%d”,&a,&b)==2){if(a+b0)printf(“OK!\n”);elseprintf(“NO~\n”);}}1/1/202034菜鸟之伤(14)总结:字符串输出的大小写问题对于菜鸟需要特别注意,其实,不管是——全大写、全小写,还是首字母大写,你尽管复制即可(没有电子版,另当别论),当然还要注意是否有标点符号等情况。说明:菜鸟常犯错误,稍有经验即可避免1/1/202035以1170BalloonComes!为例SampleInput4+12-12*12/12SampleOutput3-120.501/1/202036菜鸟之伤(15)intn,a,b,i;charp;scanf(%d,&n);for(i=0;in;i++){scanf(%c%d%d,&p,&a,&b);if(……)}1/1/202037菜鸟之伤(15)刚才程序的改进版:intn,a,b,i;charp;scanf(%d,&n);getchar();for(i=0;in;i++){scanf(%c%d%d,&p,&a,&b);if(...)……}是否还有问题?如何修改?1/1/202038菜鸟之伤(15)总结:字符和数字的混合输入带来的问题,也是一个常常困扰使用C语言编程的同学的经典问题,关键就是程序未能及时接收回车符,而误将回车当作下一组数据的首字母,你可以通过添加一句getchar();轻松解决该问题。说明:菜鸟的经典错误,如果之前没有遇到过,很难一下子反应过来,当然,遇到一次以后就不成为问题了~1/1/2020392007平方和与立方和给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和。SampleInput1325SampleOutput428201521/1/202040菜鸟之伤(16)#includestdio.hvoidmain(){intm,n;while(scanf(“%d%d”,&m,&n)==2){inti,x=0,y=0;for(i=m;i=n;i++){if(i%2==0)y=y+i*i;elsex=x+i*i*i;}printf(“%d%d\n”,y,x);}}1/1/202041菜鸟之伤(16)总结:题目并没有保证数据是递增的,但人往往有思维定势,而很多题目的设计就是针对这一点!不要埋怨,这种训练能很好的培养我们审慎的思维习惯。说明:这种错误经历过以后还是比较容易牢记的,所以说有时候经验很重要。1/1/202042菜鸟之伤(17)以下的程序输出什么?#includestdio.h#includeiostream.hintmain(){intj=0;for(j=0;j5;j++){c