常见错误类型和程序调试
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
• 原因是漏写了break语句。case只起标号的作用, 而不起判断作用,因此在执行完第一个printf函数 语句后接着执行第2、3、4、5个printf函数语句。 应改为 switch(score) {case 5:printf("Verygood!");break; case 4:printf(“Good!”); break; case 3:printf(“Pass!”); break; case 2:print(“Fail!”); break; defult:print("data error!"); }
为 while(i<=100) {sum=sum+i; i++; } • (10) 括弧不配对。 • 当一个语句中使用多层括弧时常出现这类错 误,纯属粗心所致。如: • while((c=getchar( )!='#') • putchar(c); • 少了一个右括弧。
• (11) 在用标识符时,忘记了大写字母和小写字母 的区别。 • 例如: main( ) {int a,b,c; a=2;b=3; C=A+B; printf("%d+%d=%",A,B,C); } • 编译时出错。编译程序把a和A认作是两个不同的 变量名处理,同样b和B,c和C都分别代表两个不 同的变量。
i++; • 语法并无错误。但while语句通知给系统的信息是 当i≤100时,执行“sum=sum+i;”。C系统无法辨 别程序中这个语句是否符合作者的原意,而只能 忠实地执行这一指令。这种错误比语法错误更难 检查。要求程序员有较丰富的经验。 • ③ 运行错误。程序既无语法错误,也无逻辑错误, 但在运行时出现错误甚至停止运行。例如: int a ,b ,c; scanf("%d %d",&a,&b); c=b/a; printf("c=%d\n",c);
• (9) 对应该有花括弧的复合语句,忘记加花括弧。 • 如: sum=0; i=1; while(i<=100) sum=sum+i; i++; 100 • 本意是实现1+2+…+100,即∑i。但上面的语句只 i=0 是重复了sum+1的操作,而且循环永不终止。因为 i的值始终没有改变。错误在于没有写成复合语句 形式。因此while语句的范围到其后第一个分号为 止。语句“i++;”不属于循环体范围之内。应改
13.2 程 序 调 试
• 所谓程序调试是指对程序的查错和排错。 • 调试程序一般应经过以下几个步骤: • (1) 先进行人工检查,即静态检查。在写好一个程序 以后,不要匆匆忙忙上机,而应对纸面上的程序进 行人工检查。这一步是十分重要的,它能发现程序 设计人员由于疏忽而造成的多数错误。而这一步骤 往往容易被人忽视。有人总希望把一切推给计算机 系统去做,但这样就会多占用机器时间。而且,作 为一个程序人员应当养成严谨的科学作风,每一步 都要严格把关,不把问题留给后面的工序。 为 了更有效地进行人工检查,所编的程序应注意力
13.1 常见错误分析
• 下面将初学者在学习和使用C语言(不包括C++)时 容易犯的错误列举出来,以起提醒的作用。这些 内容在以前各章中大多已谈到,为便于查阅,在 本章中集中列举,供初学者参考,以此为鉴。 • (1) 忘记定义变量。如: main( ) {x=3; y=6; printf("%d\n ",x+y); }
• (13) 混淆字符和字符串的表示形式。 char sex; sex="M"; … • sex是字符变量,只能存放一个字符。而字符常量 的形式是用单引号括起来的,应改为 • sex='M'; • “M”是用双引号括起来的字符串,它包括两个字 符:‘M’和‘\0’,无法存放到字符变量sex中。
• (14)没有注意函数参数的求值顺序。例如有以下语句: • i=3; • printf("%d,%d,%d\n",i,++i,++i); 许多 人认为输出必然是 • 3,4,5 • 实际不尽然。在Turbo C和其他一些C系统中输出是 • 5,5,4 • 因为这些系统是采取自右至左的顺序求函数参数的 值。先求出最右面一个参数(++i)的值为4,再求出第 2个参数(++i)的值为5,最后求出最左面的参数(i)的 值5。
• 输入a和b的值, 输出b/a的值, 程序没有错。 但 是如果输入a的值为0, 就会出现错误。 因此程序 应能适应不同的数据, 或者说能经受各种数据的 “考验” , 具有“健壮性”。 • 写完一个程序只能说完成任务的一半(甚至不到一 半)。调试程序往往比写程序更难,更需要精力、 时间和经验。常常有这样的情况:程序花一天就 写完了,而调试程序二三天也未能完。有时一个 小小的程序会出错五六处,而发现和排除一个错 误,有时竟需要半天,甚至更多。希望读者通过 实践掌握调试程序的方法和技术。
常见错误和程序调试
1 2 常见错误分析 程序调试
• 要真正学好C、用好C并不容易,“灵活”固然是 好事,但也使人难以掌握,尤其是初学者往往出 了错还不知怎么回事。 • C编译程序对语法的检查不如其他高级语言那样 严格(这是为了给程序人员留下“灵活”的余地)。 因此,往往要由程序设计者自己设法保证程序的 正确性。需要不断积累经验,提高程序设计和调 试程序的水平。
执行的目标程序。运行程序,输入程序所需数据, 就可得到运行结果。应当对运行结果作分析,看它 是否符合要求。应当把程序可能遇到的多种方案都 一一试到。 • (4) 运行结果不对,大多属于逻辑错误。对这类错 误往往需要仔细检查和分析才能发现。可以采用以 下办法: printf语句输出 设置断点Ctrl+F8 单步运行 F8 观测变量的值Ctrl +F7
• (5) 输入时数据的组织与要求不符。 • 用scanf函数输入数据,应注意如何组织输入数据。 在scanf输入时,除了格式控制符以外的其他字符 必须按原样输入。
• • • • • • • • •
假如有以下scanf函数: scanf("%d%d",&a,&b); 有人按下面的方法输入数据: 3,4 应该用以下方法输入: 3 4 如果scanf函数为scanf("%d,%d",&a,&b); 应按以下方法输入: 3,4 此时如果用“34”反而错了。
对于超过整个范围的数,要用long型,即改为 long int num; num=89101;
printf("%ld",num); 请注意,如果只定义num为long型,而在输出时仍 用“%d”说明符,仍会出现以上错误。
• (4) 输入变量时忘记使用地址符。如: • scanf("%d%d",a,b); • C语言要求指明“向哪个地址标识的单元送值”。 应写成scanf("%d%d",&a,&b);
建议最好不用会引起二义性的用法。如果在上例 中,希望输出“3,4,5”时,可以改用 i=3; j=i+1; k=j+1; printf("%d,%d,%d\n",i,j,k);
• 程序出错有三种情况: • ① 语法错误。指违背了C语法的规定,对这类错 误,编译程序一般能给出“出错信息”,并且告 诉你在哪一行出错。只要细心,是可以很快发现 并排除的。 • ② 逻辑错误。程序并无违背语法规则,但程序执 行结果与原意不符。这是由于程序设计人员设计 的算法有错或编写程序有错,通知给系统的指令 与解题的原意不相同,即出现了逻辑上的混乱。 例如:前面第9条错误: sum=0;i=1; while(i<=100) sum=sum+i;
a>b还是a≤b,都输出“a is larger than b”。 • 又如: for(i=0;i<10;i++); {scanf("%d",&x); printf("%d\n",x*x); } • 本意为先后输入10个数,每输入一个数后输出它 的平方值。由于在for( )后加了一个分号,使循 环体变成了空语句。只能输入一个整数并输出它 的平方值。 • 总之,在if、for、while语句中,不要画蛇添足多 加分号。
• (6) 误把“=”作为“等于”比较符。 • 在C语言中,“=”是赋值运算符,“==”才是关系 运算符“等于”。如果写成 • if(a=b) printf("a equal to b"); • C编译系统将(a=b)作为赋值表达式处理,将b的值 赋给a,然后判断a的值是否零,若为非零,则作 为“真”;若为零作为假。 • 如果a的值为3,b的值为4,a≠b,按原意不应输出 “ae q u a lt ob”。而现在输出“ae q u a lt o b”。 • 这种错误在编译时是检查不出来的,但运行结果 往往是错的。而且由于习惯的影响,程序设计者 自己往往也不易发觉。
来自百度文库
的行,如果在提示出错的行上找不到错误的话应 当到上一行再找。 如果系统提示的出错信息多,应当从上到下逐一 改正。有时显示出一大片出错信息往往使人感到 问题严重,无从下手。其实可能只有一二个错误。 例如,对所用的变量未定义,编译时就会对所有 含该变量的语句发出出错信息。只要加上一个变 量定义,所有错误都消除了。 • (3) 在改正语法错误(包括“错误”(error)和“警 告”(warning))后,程序经过连接(link)就得到可
• (2) 输入输出的数据的类型与所用格式说明符不一 致。 • 例如,若a已定义为整型,b已定义为实型。 a=3;b=4.5; printf("%f %d\n",a,b); • 编译时不给出出错信息,但运行结果将与原意不 符,输出为 • 0.000000 16402
(3) 未注意int型数据的数值范围。 • 一般微型计算机上使用的C编译系统,对一个整型 数据分配两个字节。因此一个整数的范围为 -215~215-1,即-32768~32767。常见这样的程序段: int num; num=89101; printf("%d",num); • 得到的却是23565,原因是89101已超过32767。两 个字节容纳不下89101,则将高位截去。
求做到以下几点:①应当采用结构化程序方法编 程,以增加可读性;②尽可能多加注释,以帮助理 解每段程序的作用;③在编写复杂的程序时,不要 将全部语句都写在main函数中,而要多利用函数, 用一个函数来实现一个单独的功能。这样既易于阅 读也便于调试,各函数之间除用参数传递数据这一 渠道以外,数据间尽量少出现耦合关系,便于分别 检查和处理。 • (2) 在人工(静态)检查无误后,才可以上机调试。通 过上机发现错误称动态检查。在编译时给出语法错 误的信息(包括哪一行有错以及错误类型),可以根 据提示的信息具体找出程序中出错之处并改正之。 应当注意的是:有时提示的出错行并不是真正出错
• • • • • •
(8) 在不该加分号的地方加了分号。 例如: if(a>b); printf("a is larger than b\n"); 本意为当a>b时输出“a is larger than b”的信息。 但由于在if(a>b)后加了分号,因此if语句到此结束。 即当(a>b)为真时,执行一个空语句。本来想a≤b时 不输出上述信息,但现在printf函数语句并不从属于 if语句,而是与if语句平行的语句。不论
• (12) switch语句的各分支中漏写break语句。 switch(score) {case 5:printf("Very good!"); case 4:printf("Good!"); case 3:printf("Pass!"); case 2:printf("Fail!"); defult:printf("data error!"); } • 上述switch语句的作用是希望根据score(成绩)打印 出评语。但当score的值为5时,输出为 • Very Good!Good!Pass!Fail!data error!
(7) 语句后面漏分号。 • C语言规定语句末尾必须有分号。分号是C语句不 可缺少的一部分。这也是和其他语言不同的。有 的初学者往往忘记写这一分号。如: • a=3 • b=4 • 编译时,编译程序在“a=3”后面未发现分号,就 把下一行“b=4”也作为上一行的语句的一部分, 这就出现语法错误。如果用复合语句,漏写最后 一个语句的分号,如: {t=a; a=b; b=t}