正文

C语言中使用中常见的错误分析(转)2006-05-06 15:09:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/liuwg/13621.html

分享到:

1  引言

       C语言是比较通用的一种程序设计语言,具有数据类型多样、函数丰富、运算灵活、生成目标程序效率高、应用面广、可移植性好、且可以直接对硬件系统进行控制操作等优点而受到广泛的欢迎,目前很多高校都开设了C语言课程。但由于C语言书写比较灵活,语法限制不严,对初学者来说容易出错。笔者在教学中针对学生学习C语言时常见错误进行了分析,供初学者借鉴。

2  C语言使用中常见的错误

2.1   系统设置错误编译时出现“LinkerError:Unabletoopeninputfile‘COS.OBJ’”错误信息。说明连接目录在错误,改正的方法是在菜单“Option”中“Directories”需重新设置“Includedirectories”、“Librarydirecto-ries”和“Turbocdirectories”,如果TC安装在D:\TC目录下,那么以上三项分别应设置为“D:\TC\INCLUDE”、“D:\TC\LIB”、“D:\TC\TC”,然后使用菜单“Option”→“Saveoptions”保存当前的设置。这种错误常发生在TC不是安装在C盘的根目录下,因为系统默认是C盘的设置。

2.2  大小写错误C语言规定所有的关键字必须小写,而标识符中的字母则既可以大写,也可以小写,标识符不能与关键字相同,并区分大小写字母。例如,else是关键字,不能作为标识符使用,而ELSE可以作为标识符使用。

 2.3  漏写分号、花括号在C语言中,规定一个语句必须以分号结束或花括号结束,如:intx=1;{inty=2;y+=x;printf("%d,%d\n",x,y);}应注意,复合语句中的最后一个语句仍然需要分号,最后一个“}”不能省略。比较容易忽视的是在“}”之后的分号,如一个类型的定义之后必须使用分号,包括结构体、联合体和枚举。如:structst{intx,*y;};

2.4  混淆“=”与“==”的区别在C语言中“=”是赋值运算符,不能作等号使用,这与其它高级语言是有区别的,而“==”是关系运算符,比较两个数据是否相等,且“==”比“=”优先级别高,如:main(){intx=1,y=2;printf("%d\n",x=y==x+1);}输出结果为:1。

2.5 scanf()函数输入变量漏写或多加地址运算符“&”如:intx;chars[5];scanf("%d",x);/*x前遗漏&*/scanf("%s",&s);/*s前多加了&,因为数组名是地址*/在C语言中,scanf()函数的输入项必须用地址表示,作用是:依照x在内存中的地址将x的值存入进去,而数组名s代表的是该数组在内存中的起始地址,因此,遗漏或多加地址运算符“&”必然导致错误。另注意,每次调用scanf()函数后,将返回一个整数值,其大小等于输入的字符个数,如:printf("%d\n",scanf("%d%d",&x,&y));如输入了两个数,则输出结果为2。

2.6 忽略printf()函数的求值顺序如:main(){inti=5;printf("%d,%d,%d\n",++i,i--,i+2);}程序的结果很容易误判为:6,6,7,而Turboc在执行printf()函数时,参数自右向左依次压入栈中,即先压入i+2参数的值入i--的值,最后将参数++i的值压入,弹出时则依次为++i、2,即当printf()函数中出现多项表达式输出项时,printf()按到左顺序计算各表达式的值,然后再输出结果。因此以上正确结果应为:5,5,7。

2.7 逻辑表达式的计算错误例1:main(){inti,j,k,s;i=j=k=1;s=--i||--j&&++k;

printf("i=%d,j=%d,k=%d,s=%d\n",i,j,k,s);}其输出结果易误判为:i=0,j=0,k=2,s=0其实正确的结果应该为:i=0,j=0,k=1,s=0

而例2:main(){inti,j,k,s;i=j=k=1;s=++i||--j&&++k;printf("i=%d,j=%d,k=%d,s=%d\n",i,j,k,s);}其输出结果易误判为:i=2,j=0,k=2,s=1其实正确的结果应该为:i=2,j=1,k=1,s=1出现这种误判的原因是C语言对逻辑表达式的计算顺序是先作算术运算,再进行逻辑运算。C语言对逻辑运算是这样规定的:对形如(表达式1)||(表达式2)||…的逻辑表达式进行计算时,先计算表达式1,如果其值是逻辑“假”或0,就接着计算表达式2,直到计算到第一个为逻辑“真”的表达式时,就可以判定整个逻辑表达式为逻辑“真”,其后的表达式将不被计算。对形如(表达式1)&&(表达式2)&&…的逻辑表达式进行计算时,先计算表达式1,如果其值是逻辑“真”或非0,就接着计算表达式2,直到计算到第一个为逻辑“假”的表达式时,就可以判定整个逻辑表达式为逻辑“假”,其后的表达式将不被计算。例1表达式--i||--j&&++k等价--i||(++j&&++k),由于--i的值为0(假),故要计算第二个表达式--j&&++k,--j的值为0(假),不再计算++k,--j&&++k的值为0,k的值仍然为1,故例1正确的结果应该为:i=0,j=0,k=1,s=0。同理可分析例2,++i的值为“真”(非0),就不再计算--j&&++k的值,j和k的值仍然为1,故例2正确的结果应该为:i=2,j=1,k=1,s=1。

2.8 混淆字符和字符串的表示形式如:charst="A";是错误的,'A'和"A"是完全不同的常量,'A'是字符常量,占一个字节,它可以赋值给字符变量,C语言中字符变量只能存放一个字符,而"A"是字符串常量,它包括两个字符:'A'和'\0',占二个字节,无法存放在字符变量中,C语言没有字符串变量,而用字符型数组来存放和处理字符串。如:charst[]="A";

2.9对有参宏展开的混洧宏定义命令的作用是给一些常用的对象重新命名,以便引用,进行宏定义以后,在程序中就可以用宏名来引用这些对象,在编译时,这些宏名会自动替换为原来的内容,这个替换过程称为宏展开。

例1:#defineN3#defineF(X)N*X*Xmain(){inti=1,j=2;printf("%d,%d\n",F(i+j),F(j+i));}结果极易误判为:27,27再看,

例2:#defineN3#defineF(X)N*(X)*(X)main(){inti=1,j=2;printf("%d,%d\n",F(i+j),F(j+i));}例1中出现的F(i+j)和F(j+i),在预处理时,分别被代换成N*i+j*i+j和N*j+i*j+i,例1正确的结果应该为:7,9。例2中的F(i+j)和F(j+i),在预处理时,分别被代换成N*(i+j)*(i+j)和N*(j+i)*(j+i),例2正确的结果才为:27,27。因此,在带参宏定义中,宠代换是用实参简单的代替形参,而不是先计算实参的值,再用值去替换形参,可见,在宏定义中有无括号的区别很大,稍不注意就会导致错误结果。

2.10 指针移动的问题指针与整数相加可以移动指针,这种移动指的是内存地址的变化,而不是真的有一个指针在内存中移动。如:inta[6],*p=a;使p指向数组a的第一个元素a[0],即p中存放的是a[0]的地址,p+1就是a[1]的地址,用*P可以得到a[0]的值,用*(p+1)则可得到a[1]的值。p+1与++p是不同的,p+1可以得到a[1]的地址,但p中存放的仍是a[0]的地址,容易错误以为p已经指向了a[1];而++p经过运算后,p中存放的是a[1]的地址,也就是说,p已经指向了a[1],而不再指向a[0]。

2.11 变量未初始化错误C语言中的所有变量都必须先定义后使用,变量的初始化是指在定义变量的同时被赋予初值。如:intx;printf("%d\n",x);是错误的,因为x的值不确定,而staticinty;printf("%d\n",y)是正确的,其输出结果为:0。因为C语言中,auto和register型变量若未初始化,也未赋值,其值是不确定的,x是auto型变量,所以x的值不确定;static和extern型变量若未初始化或赋值,其值为0,可以引用,所以y的值为0。

3 结束语上述列举的一些错误,是初学者在学习中经常遇到的错误,当然还会碰到其它一些不容忽视的错误,需具体情况具体分析和认真总结,只有这样才能消除这些常见错误,提高编程水平。

阅读(4995) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册