C语言调试常见错误及解决办法

上传人:飞*** 文档编号:24461089 上传时间:2017-12-05 格式:DOC 页数:9 大小:224.39KB
返回 下载 相关 举报
C语言调试常见错误及解决办法_第1页
第1页 / 共9页
C语言调试常见错误及解决办法_第2页
第2页 / 共9页
C语言调试常见错误及解决办法_第3页
第3页 / 共9页
C语言调试常见错误及解决办法_第4页
第4页 / 共9页
C语言调试常见错误及解决办法_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《C语言调试常见错误及解决办法》由会员分享,可在线阅读,更多相关《C语言调试常见错误及解决办法(9页珍藏版)》请在金锄头文库上搜索。

1、C语言调试常见错误及解决办法C语言调试常见错误及解决办法程序开发过程的各个阶段都可能发生错误,可以将程序设计中的错误分成五类:第一类,编译期错误。这是指在程序的编译过程中由编译程序识别或检查出来的错误,常称之为语法错误。诸如不符合规定的语句格式、对象说明与使用不一致、不正确的分隔符、不存在的标号、不正确的初始化数据、不恰当的循环嵌套等等。在编译期发现一个错误后,编译工作并不立即停止,而是尽可能多地找出源程序中的全部错误。第二类,连接错误。这是指连接程序在装配目标程序时发现的错误,通常由于函数名书写错误、缺少包含文件或包含文件的路径错误等原因引起的。第三类,运行期错误。这是指可执行程序执行过程中

2、发现的错误。如在计算过程中遇到了除数为零的错误、求一个负数的平方根等等。编译系统发现这类错误后如无特殊指示通常告知一些适当信息,然后立即停止程序的执行。当然,为阻止这类错误的出现,程序设计者可在程序中编入一些由自己来检查这类错误的程序段,这可能更适合于自己的处理要求。第四类,逻辑性错误。这类错误是在编译期、连接期和运行期都不能发现的错误。如程序中把log写成了log10,把x+y写成了x-y等。显然编译系统是无法查出这类错误的。第五类,警告性错误。这类错误是指编译系统在编译阶段发现程序中有一些可疑的或含混不清的地方,如源程序中发现了一个定义过但从未使用过的变量。这类情况从语法上讲是正确的,因此

3、一般不会停止编译,在大多数情况下不会阻止目标程序与可执行程序的生成、连接和运行。但是对这类错误不应掉以轻心,应仔细检查程序,这往往存在着某种潜在的运行期错误。排错是非常困难的,有可能花费很长的时间。程序设计的目标应该是避免出现太多的问题。对减少排错能有所帮助的技术包括:好的设计、好的风格、边界条件测试、合理性检查、限制全局数据等等。一、第一类错误分析1在用scanf函数给普通变量输入数据时,在变量名前漏写地址运算符&。如:scanf(%d%d,x,y);2在scanf函数调用语句中,企图规定输入实型数据的小数位。如执行以下语句:scanf(%6.2f,&a);3输入数据时的数据形式与要求不符。

4、用scanf函数输入数据时,必须注意要与scanf语句中的对应形式匹配。如:scanf(%d,%d,&x,&y);若按以下形式输入数据:2 4是不合法。数据2和4之间应当有逗号。4输入、输出时的数据类型与所用格式说明符不匹配。例如有以下说明语句:int x=1;float y=2.5;则运行时执行语句printf(x=%f,y=%dn,x,y);将给出与原意不符的结果:(在TURBO C2.0下运行)5混淆=和=。在C语言中,=赋值运算符,=是关系运算符。6在不该出现分号的地方加了分号。例如:if(xy);printf(x is larger than y.n);7对于复合语句,忘记加花括号。

5、例如:i=1;a=0;while(i0)break;printf(%dn,x);while(x!=0);11使用+或-运算符时易犯的错误。如:main()int a5=1,2,3,4,5,*p;p=a;printf(%dn,*(p+);12误解形参值的变化会影响实参的值。例如:main()int a=1,b=3;swap(a,b);printf(a=%d,b=%dn,a,b);swap(x,y)int x,y;int m;m=x;x=y;y=m;原意想通过调用swap函数使a与b的值对换,然而,从输出结果可知a和b的值并未进行交换。二、第二类错误分析1在使用变量前未定义。例如:main()a=

6、1;b=2;printf(%dn,a+b);2语句后面漏写分号或不该加分号的地方加了分号。C语言规定,语句必须以分号结束,分号是C语句不可缺少的一部分,这也是和其它高级语言不同的一点。初学者往往容易忽略这个分号。如:x=1 y=2;又如在复合语句中漏写最后一个语句的分号:t=x;x=y;y=t 3不该有空格的地方加了空格例如,在用/*.*/对C程序中的任何部分作注释时,/与*之间都不应当有空格。又如,在关系运算符=,=和!=中,两个符号之间也不允许有空格。4定义或引用数组的方式不对。C语言规定,在对数组进行定义或对数组元素进行引用时必须要用方括号(对二维数组或多维数组的每一维数据都必须分别用方

7、括号括起来),例如以下写法都将造成编译时出错:int a(10);int b5,4;printf(%dn,b1+2,2);5混淆字符和字符串C语言中的字符常量是由一对单引号括起来的单个字符;而字符串常量是用一对双引号括起来的字符序列。字符常量存放在字符型变量中,而字符串常量只能存放在字符型数组中。例如,假设已说明num是字符型变量,则以下赋值语句是非法的:num=1;6在引用数组元素或指针变量之前没对其赋初值。例如:main()main()int a6,b;int*ptr,i=1;b=a5;*ptr=i以上两个程序段在编译时均会出现警告信息。7混淆数组名与指针变量在C语言中,数组名代表数组的首

8、地址,它的值是一个常量,不能被修改。例如,在以下程序段中,用a+是不合法的。main()int i,a10;for(i=0;i10;i+)scanf(%d,a+);8混淆不同类型的指针。若有以下语句:int*p1,a=1;float*p2;p1=&a;则赋值语句p2=p1是非法的。9混淆指针说明语句中的*号和执行语句中的*号。设有以下说明语句:int*p1,i=1;则*p1=&i;是不合法的。10误将函数形参和函数中的局部变量一起定义。例如:fun(x,y)float x,y,z;x+;y+;z=x+y;11所调用的函数在调用前未定义。main()float a=10,b=20,c;c=fun

9、(a,b);float fun(x,y)float x,y;x+;y+;12混淆结构体类型名和结构体变量名。若定义了以下结构体类型student:struct studentlong int num;char name20;int age;float score;则赋值语句:student.num=199401;是错误的。三、诊断错误及其处理防止程序出错的第一关是编译器。如果遇到约束违规的情况或语法错误,编译器至少会生成一个诊断错误信息。大多数编译器将其诊断信息分为两类:错误和警告。语法错误很常见,也较易修改。调试程序时首先要改正的是语法错误,调试本身是一种艺术,是程序中断时试着去修复的一种艺

10、术。糟糕的语法会使编译器混乱,甚至可能达到生成很多错误的程度,程序设计者对这种情况不要大惊小怪,应冷静对待,其实很可能仅仅是由于某一个语句引起的,比如说漏掉了while循环中的一个大括号或语句末尾键入了冒号而非分号等。为此我们应该养成一种习惯,自顶向下的修改方法,每次从错误表的开头开始,一次修改一、二个错误再编译,或许错误就能减少许多甚至全部语法错误。模块化程序设计也有助于程序的排错。调试一个充满连接和转折、全局变量等的程序要比调试一个精心设计的模块化程序困难得多。如果程序分成几个模块,各个模块负责程序的一个专项功能,一旦识别出问题可能所处的模块,就很容易地通过检查源代码方式来发现错误,这种策

11、略也称为分治法,因为如果知道了没有问题之处,几乎等同于知道了问题发生的地方。有时我们也可以忽略警告,但这并非是一种良好的编程习惯,追踪每个警告的原因并认真考虑是否有更稳健的方法编写代码能够帮助编程者编写更好的代码。如果我们只是忽略它,当这些无害的警告不断累积到一定程度时,可能面临出现混乱的危险。词法陷井及其分析处理1)=不同于=这是初学者最易犯的一个错误,符号=作为赋值运算符,符号=作为比较。一般而言,赋值运算相对于比较运算出现得更频繁,因此,字符数少的符号=就被赋予了更常用的含义赋值运算。此外,在C语言中赋值符号被作为一种操作符对待,因而重复进行赋值运算(如a=b=c=5)可很容易地书写,并

12、且赋值操作还可以嵌入到更大的表达式中。这种使用上的便利性可能导致一个潜在的问题:本意是作比较运算时,却可能无意中误写成了赋值运算。该错误大多数情况下可以通过简单的要素项重排而防止。从编译器的角度出发,对于相等测试,变元在等号的哪一边无关紧要,如果两边都是变量,则需要留意符号=的个数。但是,如果一边是常量,则存在可以防止错误的适当措施。我们何不养成把常量放在比较运算符左边的习惯呢?因为这样一来,即便漏掉了一个=符号,保证会出现一个编译错误,因为不能给常数赋值。(2)字符与字符串C语言中的单引号和双引号含义迥异,用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序

13、列值,因此,采用ASCII字符集的编译器而言,a的含义与0141或97严格一致。而用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为零的字符message初始化。整型数(一般为16位或32位)的存储空间中可以容纳多个字符(一般为8位),因此,有的C编译器允许在一个字符常量(以及字符串常量)中包含多个字符。也就是说,用yes代替yes不会被编译器检测到,后者的含义是依次包含y、e、s以及字符message的4个连续内存单元的首地址,而前者的含义并没有正确地定义,有些C编译器会处理成出错,但大多数C编译器的理解为一个整数值,由y、e、s

14、所代表的整数值按照特定编译器实现中定义的方式组合得到。因此,这两者如果在数值上有什么相似之处,也完全是一种巧合而已。(3)整数溢出C语言为编程者提供了三种不同长度的整数:short int、int和long int,但不管是哪种类型表示的整数总有一定的范围,越出该范围时称为整数的溢出。例如现有算法要求如下:求满足条件1+2+3+n32767的最大整数n,请考察如下程序段:int n=1,sum=0;while(sum=32767)sum+=n;n+;printf(n=%dn,n-1);乍看该程序时无错误,但事实上,上列程序中的while循环是一个无限循环,原因在于int型数的表示范围为-327

15、68到+32767,当累加和sum超过32767时,便向高位进位,而对int型数而言,最高位表示符号,故sum超过32767后便得到一个负数,while条件当然满足,从而形成无限循环。此时,最好的解决办法是将sum定义为long int型。(4)词法分析中的贪心法C语言中的某些符号,例如/、*、=、+等,只有一个字符长,称为单词符符号。而/*、=、+等包含了多个字符,称为多字符符号。当C编译器读入一个字符/后又跟了一个字符*,那么编译器就必须做出判断:是将其作为两个分别的符号对待,还是合起来作为一个符号对待。C语言的处理策略是贪心法,即从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如可能,再读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号为止。所以a-b:应理解为(a-)-b;而将描述命题x除以p所指向的值时,应书写为:y=x/(*p);而不要写为:y=x/*p,因为编译器将/*理解为一段注释的开始。我最近在玩和讯微博,很方便,很实用,你也来和我一起玩吧!去看看我的微博吧!

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号