c程序第16章-常见错误和程序调试.ppt
《c程序第16章-常见错误和程序调试.ppt》由会员分享,可在线阅读,更多相关《c程序第16章-常见错误和程序调试.ppt(60页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第第1616章章 常见错误和程序调试常见错误和程序调试16.1常见错误分析常见错误分析16.2程序调试程序调试要真正学好C、用好C并不容易,“灵活”固然是好事,但也使人难以掌握,尤其是初学者往往出了错还不知怎么回事。C编译程序对语法的检查不如其他高级语言那样严格(这是为了给程序人员留下“灵活”的余地)。因此,往往要由程序设计者自己设法保证程序的正确性。调试一个C程序要比调试一个PASCAL或FORTRAN程序更困难一些。需要不断积累经验,提高程序设计和调试程序的水平。C语言有些语法规定和其他高级语言不同,学习过其他高级语言的读者往往按照使用其他高级语言的习惯来写C程序,这也是出错的一个原因。1
2、6.1常见错误分析下面将初学者在学习和使用C语言(不包括C+)时容易犯的错误列举出来,以起提醒的作用。这些内容在以前各章中大多已谈到,为便于查阅,在本章中集中列举,供初学者参考,以此为鉴。(1)忘记定义变量。如:main()x=3;y=6;printf(%dn,x+y);C要求对程序中用到的每一个变量都必须定义其类型,上面程序中没有对x、y进行定义。应在函数体的开头加intx,y;这是学过BASIC和FORTRAN语言的读者写C程序时常见的一个错误。在BASIC语言中,可以不必先定义变量类型就可直接使用。在FORTRAN中,未经定义类型的变量按隐含的I-N规则决定其类型,而C语言则要求对用到的
3、每一个变量都要在本函数中定义(除非已定义为外部变量)。(2)输入输出的数据的类型与所用格式说明符不一致。例如,若a已定义为整型,b已定义为实型。a=3;b=45;printf(%f%dn,a,b);编译时不给出出错信息,但运行结果将与原意不符,输出为000000016402它们并不是按照赋值的规则进行转换(如把45转换成4),而是将数据在存储单元中的形式按格式符的要求组织输出(如b占4个字节,只把最后两个字节中的数据按%d,作为整数输出)。(3)未注意int型数据的数值范围。一般微型计算机上使用的C编译系统,对一个整型数据分配两个字节。因此一个整数的范围为-215215-1,即-3276832
4、767。常见这样的程序段:int num;num=89101;printf(%d,num);得到的却是23565,原因是89101已超过32767。两个字节容纳不下89101,则将高位截去。见图16.1。即将超过低16位的数截去。即将89101减去216(即16位二进制所形成的模)。89101-65536=23565。图16.1有时还会出现负数。例如num=196607;输出得-1。因为196607的二进制形式为00 00 00 00 00 00 00 1011 11 11 11 11 11 11 11去掉高位10,低16位的值是-1(-1的补码是:1111111111111111)。对于超过
5、整个范围的数,要用long型,即改为long intnum;num=89101;printf(%ld,num);请注意,如果只定义num为long型,而在输出时仍用“%d”说明符,仍会出现以上错误。(4)输入变量时忘记使用地址符。如:scanf(%d%d,a,b);这是许多初学者刚学习C语言时一个常见的疏忽,或者说是习惯性的错误,因为在其他语言中在输入时只需写出变量名即可,而C语言要求指明“向哪个地址标识的单元送值”。应写成scanf(%d%d,&a,&b);(5)输入时数据的组织与要求不符。用scanf函数输入数据,应注意如何组织输入数据。假如有以下scanf函数:scanf(%d%d,&a
6、,&b);有人按下面的方法输入数据:3,4这是错的。数据间应该用空格来分隔。读者可以用printf(%d%d,a,b);来验证一下。应该用以下方法输入:34如果scanf函数为scanf(%d,%d,&a,&b);对scanf函数中格式字符串中除了格式说明符外,对其他字符必须按原样输入。因此,应按以下方法输入:3,4此时如果用“34”反而错了。还应注意,不能企图用scanf(input a&b:%d,%d,&a,&b);想在屏幕上显示一行信息:input a&b:然后在其后输入a和b的值,这是不行的。这是由于有的读者以为scanf具有BASIC语言中的INPUT语句的功能(先输出一个字符串,再
7、输入变量的值)。如果想在屏幕上得到所需的提示信息,可以另加一个printf函数语句:printf(input a&b:);scanf(%d,%d,&a,&b);(6)误把“=”作为“等于”比较符。在许多高级语言中,用“=”符号作为关系运算符“等于”。例如,在BASIC或PASCAL程序中都可以写if(a=b)then但在C语言中,“=”是赋值运算符,“=”才是关系运算符“等于”。如果写成if(a=b)printf(a equal to b);C编译系统将(a=b)作为赋值表达式处理,将b的值赋给a,然后判断a的值是否零,若为非零,则作为“真”;若为零作为假。如果a的值为3,b的值为4,ab,按
8、原意不应输出“ae q u a lt ob”。而现在先将b的值赋给a,a也为4,赋值表达式的值为4。if语句中的表达式值为真(非零),因此输出“ae q u a lt o b”。这种错误在编译时是检查不出来的,但运行结果往往是错的。而且由于习惯的影响,程序设计者自己往往也不易发觉。(7)语句后面漏分号。C语言规定语句末尾必须有分号。分号是C语句不可缺少的一部分。这也是和其他语言不同的。有的初学者往往忘记写这一分号。如:a=3b=4编译时,编译程序在“a=3”后面未发现分号,就把下一行“b=4”也作为上一行的语句的一部分,这就出现语法错误。有时编译时指出某行有错,但在该行上并未发现错误,应该检查
9、上一行是否漏了分号。如果用复合语句,有的学过PASCAL语言的读者往往漏写最后一个语句的分号,如:t=a;a=b;b=t 在PASCAL中分号是两个语句间的分隔符而不是语句的一部分,而在C中,没有分号的就不是语句。(8)在不该加分号的地方加了分号。例如:if(ab);printf(aislarger than bn);本意为当ab时输出“aislarger than b”的信息。但由于在if(ab)后加了分号,因此if语句到此结束。即当(ab)为真时,执行一个空语句。本来想ab时不输出上述信息,但现在printf函数语句并不从属于if语句,而是与if语句平行的语句。不论ab还是ab,都输出“a
10、 is larger than b”。又如:for(i=0;i10;i+);scanf(%d,&x);printf(%dn,x*x);本意为先后输入10个数,每输入一个数后输出它的平方值。由于在for()后加了一个分号,使循环体变成了空语句。只能输入一个整数并输出它的平方值。总之,在if、for、while语句中,不要画蛇添足多加分号。(9)对应该有花括弧的复合语句,忘记加花括弧。如:sum=0;i=1;while(i=100)sum=sum+i;i+;本意是实现1+2+100,即i。但上面的语句只是重复了sum+1的操作,而且循环永不终止。因为i的值始终没有改变。错误在于没有写成复合语句形式
11、。因此while语句的范围到其后第一个分号为止。语句“i+;”不属于循环体范围之内。应改100i=0为while(i=100)sum=sum+i;i+;(10)括弧不配对。当一个语句中使用多层括弧时常出现这类错误,纯属粗心所致。如:while(c=getchar()!=#)putchar(c);少了一个右括弧。(11)在用标识符时,忘记了大写字母和小写字母的区别。例如:main()inta,b,c;a=2;b=3;C=A+B;printf(%d+%d=%,A,B,C);编译时出错。编译程序把a和A认作是两个不同的变量名处理,同样b和B,c和C都分别代表两个不同的变量。(12)引用数组元素时误用
12、了圆括弧。如:main()int i,a(10);for(i=0;i10;i+)scanf(%d,&a(i);C语言中对数组的定义或引用数组元素时必须用方括弧。(13)在定义数组时,将定义的“元素个数”误认为是“可使用的最大下标值”。main()int a10=1,2,3,4,5,6,7,8,9,10;int i;for(i=1;i=10;i+)printf(%d,ai);想输出a1到a10。但一些初学者常犯的错误。C语言规定定义时用a10,表示a数组有10个元素,而不是可以用的最大下标值为10。数组只包括a0到a910个元素,因此用a10就超出a数组的范围了。(14)对二维或多维数组的定义和
13、引用的方法不对。main()int a5,4;printf(%d,a1+2,2+2);对二维数组和多维数组在定义和引用时必须将每一维的数据分别用方括弧括起来。上面a5,4应改为a54,a1+2,2+2应改为a1+22+2。根据C的语法规则,在一个方括弧中的是一个维的下标表达式,a1+2,2+2中方括弧中的“1+2,2+2”是一个逗号表达式,它的值是第二个数值表达式的值,即2+2的值为4。所以a1+2,2+2相当于a4。而a4是a数组的第4行的首地址。因此执行printf函数输出的结果并不是a34的值,而是a数组第4行的首地址。(15)误以为数组名代表数组中全部元素。例如:main()int a
14、4=1,3,5,7;printf(%d%d%d%dn,a);企图用数组名代表全部元素。在C语言中,数组名代表数组首地址,不能通过数组名输出4个整数。(16)混淆字符数组与字符指针的区别。main()char str4;str=Computer and c;printf(%sn,str);编译出错。str是数组名,代表数组首地址。在编译时对str数组分配了一段内存单元,因此在程序运行期间str是一个常量,不能再被赋值。因此,str=“Computer and c”是错误的。如果把“char str4;”改成“charstr;”,则程序正确。此时str是指向字符数据的指针变量,str=“Compu
15、ter and c”是合法的,它将字符串的首地址赋给指针变量str,然后在printf函数语句中输出字符串“Computer and c”。因此应当弄清楚字符数组与字符指针变量用法的区别。(17)在引用指针变量之前没有对它赋予确定的值。main()char*p;scanf(%s,p);没有给指针变量p赋值就引用它,编译时给出警告信息。应当改为charp,c20;p=c;scanf(%s,p);即先根据需要定义一个大小合适的字符数组c,然后将c数组的首地址赋给指针变量p,此时p有确定的值,指向数组c。再执行scanf函数就没有问题了,把从键盘输入的字符串存放到字符数组c中。(18)switch语
16、句的各分支中漏写break语句。例如:switch(score)case 5:printf(ery good!);case 4:printf(Good!);case 3:printf(Pass!);case 2:printf(Fail!);defult:printf(data error!);上述switch语句的作用是希望根据score(成绩)打印出评语。但当score的值为5时,输出为ery Good!Good!Pass!Fail!data error!原因是漏写了break语句。case只起标号的作用,而不起判断作用,因此在执行完第一个printf函数语句后接着执行第2、3、4、5个pr
17、intf函数语句。应改为switch(score)case 5:printf(erygood!);break;case 4:printf(Good!);break;case 3:printf(Pass!);break;case 2:print(Fail!);break;defult:print(data error!);(19)混淆字符和字符串的表示形式。char sex;sex=M;sex是字符变量,只能存放一个字符。而字符常量的形式是用单引号括起来的,应改为sex=M;“M”是用双引号括起来的字符串,它包括两个字符:M和0,无法存放到字符变量sex中。(20)使用自加(+)和自减(-)运算
18、符时出的错误。例如:main()intp,a5=1,3,5,7,9;p=a;printf(%d,*p+);不少人认为“*p+”的作用是先使p加1,即指向第1个元素a1处,然后输出第一个元素a1的值3。其实应该是先执行p+,而p+的作用是先用p的原值,用完后使p加1。p的原值指向数组a的第0个元素a0,因此*p就是第0个元素a0的值1。结论是先输出a0的值,然后再使p加1。如果是*(+p),则先使p指向a1,然后输出a1的值。(21)有人习惯用传统的方式对函数形参进行声明,但却把对函数的形参和函数中的局部变量混在一起定义。如:max(x,y)int x,y,;=xy?x,y;return();应
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序 16 常见 错误 调试
限制150内