首页 > 试题

辽宁石油大学

更新时间:2023-02-02 02:13:00 阅读: 评论:0

九年级分数查询-五级风


2023年2月2日发(作者:2015年立春时间)

第10章

常见错误和程序调试

Commonerrorandprogramdebug

本章概要

Summaryofthechapter

程序调试是程序设计过程中一个必不可少的环节,调试过程中的错误处理则是保证程序正确性的必

要手段。本章将常见的一些错误列举出来,以方便进行程序调试。

C语言是一种介于高级语言与低级语言之间的中级语言,允许直接访问物理地址,能

进行位操作,可以直接对硬件进行操作。程序员使用C语言编写程序会感到限制少、灵活

性较大、功能强,可以编写出能解决复杂问题的、运行效率高、占用内存少的高质量程序,

不仅用来编写系统软件,也用来编写应用软件,所以得到广泛应用。正因为如此,C语言

受到愈来愈广泛的重视,从初学者到高级软件人员,都在学习C和使用C语言。

但是要真正学好、用好C并不容易。因为C语言允许编程人员有较大的自由度,从

而放宽了语法检查,C编译程序对语法的检查不如其他高级语言那样严格,因此,往往要

由程序设计者自己设法保证程序的正确性。这就使人感到难以掌握,尤其是初学者,容易

出错,出了错还不知什么原因、如何处理。另外,C语言有些语法规定和其他高级语言不

同,学习过其他高级语言的读者往往按照使用其他高级语言的习惯来写C程序,这也是出

错的一个原因。

调试一个C程序要比调试一个其它高级语言的程序更困难一些。需要不断积累经验,

提高程序设计和调试程序的水平。

10.1常见错误分析(Commonerroranaly)

程序出错有三种情况:

①语法错误。由于违背了C语言的语法规定而引起的。如双引号或括号不全、do-while

语句缺少while、使用关键字作变量名等,对这类错误,编译程序一般都能检测出来,给出

“出错信息”。并且告诉你在哪一行出错。只要细心,是可以很快发现并排除的。

②逻辑错误。由于程序的结构或算法错误引起的。程序并没有语法错误,程序运行过

程中也没有发生错误,只是最后的运行结果并不是希望的结果。例如,有下面的程序段:

main()

{intsum=0,i=1;

while(i<=100)

·204·第10章常见错误和程序调试

sum=sum+i;

i++;

printf("%dn",sum);

}

语法并无错误。但程序运行时陷入“死循环”,因为while循环语句中,起判断条件的

表达式“i<=100”始终为“真”。C系统无法辨别程序中这个语句是否符合设计者的原意,

而只能忠实地执行这一指令。这种错误比语法错误更难检查。要求程序员有较丰富的经验。

③运行错误。程序既无语法错误,也无逻辑错误,但在运行时出现错误甚至停止运行。

例如:

main()

{inta,b,c;

scanf("%d%d",&a,&b);

c=b/a;

printf("%dn",c);

}

程序没有语法错误,但是程序运行过程中,如果输入数据时a的值为0,就会产生:

Divisionbyzero的错误,即在除法运算中“0”作了除数。

C程序错误检测的首要工具是编译程序,它能把语法上的错误找到并分离出来以信息

的形式显示,显示的信息分:错误(error)和警告(warning)。错误(error)将影响程序执

行,而警告(warning)一般不影响程序的执行,但会影响结果的正确性。

下面将初学者在学习和使用C语言时容易犯的错误列举出来,这些内容在前面各章中

大多己谈到,为便于查阅,在本节集中列举,供初学者参考。

1.数据定义类错误(Errorofdatadefinitionclass)

(1)忘记定义变量。如有:

main()

{x=3;

y=6;

z=x+y;

printf("%dn",z);

}

编译时将出现error信息:

Undefinedsymbol'xxx'

原因是C要求对程序中用到的每一个变量都必须先定义后使用,上面程序中没有对x、

y、z进行定义。应在函数体的开头加上:

intx,y,z;

另外还要注意,C语言中标识符的大小写是不同的,如果定义与使用时大小写不一致

也会出现这样的错误。如有

inta=2,b=3,c;

c=a+B;

第10章常见错误和程序调试·205·

系统会认为“B”没有定义。这是学过BASIC语言的读者常犯的错误,因为BASIC

语言中标识符不分大小写。也可能出现下面情况:

Floatf;

这也是不合法的,C语言的关键字不允许大写。

(2)定义变量的位置错误。如:

main()

{inta,b;

scanf("%d%d",&a,&b);

intc;

c=a+b;

printf("%d",c);

}

编译时将出现error信息:

Expressionsyntax

原因是将变量定义“intc;”放在执行语句后面,系统将其作为一个表达式语句处理,

而不再作为变量的定义。

(3)定义整型变量时没有考虑其数值范围。如有:

inta;

a=45678;

printf("%d",a);

编译时并无错误,但输出的值不是45678,而是-19858,原因是int数的范围为-215~215-1,

即-32768~32767,45678已超出了int型的数值范围。为此可以采用long型,即改为

longinta;

a=45678;

printf("%ld",a);

请注意,如果只定义a为long型,而在输出时仍用“%d”说明符,仍会出现以上错误。

(4)混淆字符与字符串的区别。如有:

charc="a";

编译时将出现warning信息:

Non-portablepointerassignment

原因是定义的字符变量c只能存放一个字符,但赋给它的值"a"是字符串,它包含两个

字符'a'和'0'。C语言对字符串按字符数组处理,是一个指针量,所以系统认为程序将一个

指针量赋给了一个非指针量。改正时,要么将c定义为字符数组或指针变量,要么按以下

方式给字符变量赋值。

①直接赋以字符常量,如:charc='a';

②赋以“转义字符”,如:charc='0';

③赋以一个字符的ASCII码,如:charc=97;

(5)曾经定义并给变量赋值,但程序中没有使用该变量。如有:

main()

·206·第10章常见错误和程序调试

{inta=1,b=2,c=3;

printf("%d,%d",a,b);

}

编译时将出现warning信息:

'c'isassignedavaluewhichisneverud

(6)宏定义或文件包含时漏掉了“#”号。如有:

defintPI3.14159

include"stdio.h"

编译时将出现error信息:

Declarationsyntaxerror

(7)混淆结构体类型与结构体变量的区别。如有:

structstudent

{longintnum;

charname[20];

charx;

};

=123;

strcpy(,"zhangfang");

='M';

编译时将出现error信息:

Undefinedsymbolstudent

Illegalstructureoperation

原因是混淆了结构体类型与结构体变量的区别,student是定义的结构体类型而不是结

构体变量,直接对结构体类型student进行操作是非法的。应当在结构体类型定义的同时或

之后,定义一个属于该类型的变量,如:

structstudentstu;

然后对结构体变量stu进行相应的操作。

2.格式类错误(Errorofformatclass)

(1)语句后面遗漏分号。如有:

printf("Goodmorning?n")

编译时的错误信息为:

Statementmissing;

原因是分号是C程序中语句的必要组成部分,每个语句必须以分号结束。这也是与其

它高级语言不同的地方。如果是复合语句,有些初学者往往遗漏最后一个语句的分号。如:

{t=a;a=b;b=t}

(2)在不该加分号的地方加了分号,如有:

for(i=0;i<10;i++);

scanf("%d",a[i]);

第10章常见错误和程序调试·207·

程序并无错误,但程序的执行结果与原意不符。程序的本意是用for循环输入10个整

数给一维数组,但在for后面加上分号后,就单独构成了一个语句,成为一个空循环,实

现不了设计思想。这种错误属于逻辑错误。

请读者注意,这是一个常见的错误,尤其是在if、for、while语句中要特别注意。

(3)括弧不配对。

包括三种情况:花括号、中括号、圆括号不配对。这类错误,纯属粗心所致。

①花括号不配对,编译将会出现error信息:

Compoundstatementmissing}

当一个语句中使用多层花括弧时常出现这种错误。

②中括号不配对,由于形式不同,编译时出现error信息也不相同,主要在数组的定

义或引用中出现这种错误。

③圆括号不配对,由于形式不同,编译时出现error信息也各不相同,主要出现在需

要使用多层圆括号的复杂表达式中、函数调用中及带圆括号的语句中,像if、switch、for、

while、do-while等语句。如:

while((c=getchar()!='#')

putchar(c);

编译时出现error信息:

Callofnon-function

Whilestatementmissing)

系统认为调用了没有定义的函数并且while语句后的圆括号不配对。

(4)赋值格式错误。如有:

b++=a+7;

编译时将出现error信息:

Lvaluerequired

原因是赋值号“=”左边应该是变量,而不能是表达式。将表达式a+7的值赋给表达

式b++是不符合C语法规定的。另外,当对符号常量重新赋值时也会出现这种错误。如有:

#definePRICE30

PRICE=40;

编译系统也会认为“PRICE=40”这个赋值表达式不符合C语言的语法规定。因为PRICE

是一个符号常量,而不是变量。

(5)输入输出的数据的类型与所用格式说明符不一致。如:

inta=3;

floatb=4.5;

printf("%f%dn",a,b);

编译时并无出错信息,但运行结果将与原意不符,输出结果为

0.000000l6402

原因是系统并不是按照赋值的规则进行数据转换的(如把4.5转换成4),而是将数据在

存储单元中的具体存放形式按格式符的要求重新组织进行输出的。变量b在内存中占4个

字节,输出时只把最后两个字节中的数据按%d格式输出。这属于逻辑上的错误。输入输

·208·第10章常见错误和程序调试

出数据时一定要注意数据类型与格式说明一致,可改为

printf("%d%fn",a,b);

(6)scanf函数中忘记使用地址运算符&。如:

main()

{inta,b,sum;

scanf("%d%d",a,b);

sum=a+b;

printf("sum=%dn",sum);

}

编译时将出现warning信息:

Possibleuof'a'beforedefinition

Possibleuof'b'beforedefinition

原因是系统认为变量a、b在参加运算前没有被赋值。用scanf函数给变量输入数据,

是要把数据放到变量在内存所占的存储单元中去,如果不使用地址运算符&,就得不到变

量的地址,所以变量a、b就得不到数据。

这是许多初学者刚学习C语言时一个常见的疏忽,或者说是习惯性的错误。因为在其

他语言中输入数据时只需写出变量名即可(如BASIC语言中的INPUT语句),而C语言

要求必须指明“向哪个地址标识的单元送值”。应写成

scanf("%d%d",&a,&b);

另外,在程序中直接使用未赋值的变量时,也出现这样的警告信息。如有:

inta,b;

a=b;

(7)输入时数据的组织与要求不符。

用scanf函数输入数据,应注意输入数据的格式,如有:

scanf("%d%d",&a,&b);

有人按下面的方法输入数据:

3,4

这是错误的。可以用

printf("%d%d",a,b);

来验证一下,输出的结果与输入的原始数据是不同的。输入时数据间应该用空格(或Tab键,

回车键)来分隔,即应该用以下方法输入:

34

如果scanf函数为:

scanf("%d,%d",&a,&b);

格式字符串中除了格式说明符外,对其他字符必须按原样输入。因此,应按以下方法输入:

3,4

此时如果用“34”反而错了。还应注意,不能企图用

scanf("inputa&b:%d,%d",&a,&b);

想在屏幕上显示一行信息:

第10章常见错误和程序调试·209·

inputa&b:

然后在其后输入a和b的值,这是不行的,只能写成:

printf("inputa&b:");

scanf("%d,%d",&a,&b);

scanf与BASIC语言中INPUT语句的功能并不完全相同。

(8)混淆赋值号(=)与比较符(==)。如有:

if(a=b)printf("aequalb");

编译时将出现warning信息:

possiblyincorrectassignment

原因是系统认为程序中将一个赋值表达式“a=b”作为if语句的条件表达式。这种错

误在if、while或do-while语句中常见。也是学过BASIC语言常犯的错误,因为在BASIC

语言中,“=”既可作为赋值号,也可作为关系运算符“等于”,但在C中,“=”是赋值运

算符,“==”才是比较用的关系运算符“等于”。

(9)错误引用寄存器变量的地址。如有:

registerinta;

scanf("%d%d",&a,&b);

或有:

registerinta;

int*p;

p=&a;

编译时将出现error信息:

Musttakeaddressofmemorylocation

原因是地址运算符&只能取内存单元的地址,而不能取寄存器变量的地址。寄存器变

量没有地址。

(10)do语句中少了while。如有:

do

{sum=sum+n;

n++;

}

编译时将出现error信息:

Dostatementmusthavewhile

(11)do语句后while缺少分号

do

{sum=sum+n;

n++;

}while(n<=100)

编译时将出现error信息:

Do-whilestatementmissing;

(12)switch语句的各分支中漏写break语句。如有:

·210·第10章常见错误和程序调试

switch(score)

{ca5:printf("Verygood!");

ca4:printf("Good!");

ca5c3:printf("Pass!");

ca2:printf("Fail!");

default:printf("Dataerror!");

}

编译时并无错误,但运行结果不是企望的结果。上述switch语句的作用是希望根据

score(成绩)打印出评语。但当score的值为5时,输出结果为

VeryGood!Good!Pass!Fail!Dataerror!

原因是漏写了break语句。ca只起标号的作用,而不起判断作用,因此在执行完第

一个printf函数语句后接着执行第2、3、4、5个printf函数语句。解决的办法就是在每个

ca分支的后面加上一条break语句。

这样的错误在编译阶段是发现不了的,只有对执行结果进行分析后才能发现错误。

(13)对浮点数进行移位操作。如有:

main()

{floata,b=12.4;

a=b<<2;

printf("%f,%f",a,b);

}

编译时将出现error信息:

Illegaluoffloatingpoint

原因是对浮点数进行了不合法的运算。

3.数组类错误(Errorofarrayclass)

(1)直接引用没有定义的数组。如有:

main()

{inti;

for(i=0;i<10;i++)

scanf("%d",a[i]);

}

编译时将出现error信息:

Invalidindirection

原因是,C要求对程序中用到的数组必须先定义后使用,上面程序中没有对数组a进

行定义就直接引用了数组元素a[i]是无效。应当在函数体的开头加上数组定义:

inta[10];

这是学过BASIC语言的读者常犯的一个错误。在BASIC语言中,对元素个数在10

以下的数组可以不经定义直接使用。

(2)对数组进行动态定义。如有:

intn=10;

第10章常见错误和程序调试·211·

inta[n];

编译时将会出现error信息:

Constantexpressionrequired

原因是,C语言要求定义数组时数组的大小必须是常量或常量表达式。另外,定义二

维数组时如果将两个维数都放在一个中括号内,也会出现这种错误。如:

inta[3,5];

C语言把方括号中的“3,5”看成是一个逗号表达式,这也是学过BASIC语言的读

者常犯的错误。应改为:

inta[3][5];

即C语言中多维数组的每一维都要放到一个方括号中。

(3)引用数组元素时,下标越界。如有:

main()

{inta[10],inti;

for(i=1;i<=10;i++)

a[i]=i*i;

}

编译时并无错误,但这样做的后果可能非常严重。这是一些初学者常犯的错误,将数

组定义时的“元素个数”误认为是“可使用的最大下标值”。C语言规定,定义时用a[l0]

表示a数组有10个元素,下标从0开始,这10个数组元素是a[0]到a[9],因此引用元素

a[10]就超出a数组的范围了,但编译系统并不认为有错。因为系统并不对数组元素作下标

检查,所以只有靠程序设计人员来保证所引用的数组元素下标不越界,以避免可能对内存

中的其他数据造成破坏。

(4)定义数组或引用数组元素时误用了圆括弧。如有:

main()

{inti,a[10];

for(i=0;i<10;i++)

scanf("%d",&a(i));

}

编译时将出现error信息:

Callofnon-function

原因是系统认为调用了一个未定义的函数a(i)。同样,如果是在定义时出现了圆括号,

如:

inti,a(10);

编译时将出现error信息:

Functiondefinitionoutofplace

系统认为在函数内又定义了函数a(10),即出现了C语言禁止的函数嵌套定义。C语

言中定义数组或引用数组元素时必须用方括号,不要与BASIC语言混淆。

(5)误以为数组名代表数组中全部元素。如有:

·212·第10章常见错误和程序调试

main()

{inta[4]={1,3,5,7};

printf("%d%d%d%dn",a);

}

编译时并无错误,但得到的是不可预知的结果。原因是企图用数组名代表数组的4个

元素,但在C语言中,数组名只能代表数组的首地址,并不代表数组的全部元素。应改为:

printf("%d%d%d%dn",a[0],a[1],a[2],a[3]);

(6)混淆字符数组与字符指针的区别。如有:

charc[20];

c="Hello!";

编译时将出现error信息:

Lvaluerequired

原因仍然是系统认为赋值错误。C语言中,字符数组名虽然代表数组的首地址,但它

是一个常量,不能被赋值。应弄清字符数组与字符指针变量用法的区别。如要对字符数组

赋值,可采用以下方法:

①在定义字符数组的同时初始化。如:

charstr[20]="Hello!";

②用字符串函数strcpy()。如:

charstr[20];

strcpy(str,"Hello!");

③用字符型指针变量。如:

char*p;

p="Hello!";

4.函数类错误(Errorsoffunctionclass)

(1)用传统方式定义函数时把形参与函数中的局部变量一起定义。如:

max(x,y)

intx,y,z;

{z=x>y?x:y;

returnz;

}

编译时将出现error信息:

'z'notanargument

undefinedsymbol'z'

原因是系统认为z既不是函数max的参数也不是局部变量。函数的形参与函数内部的

局部变量定义位置是不同的,形参应该放在函数体之前定义,而局部变量则应该放在函数

体中的说明部分进行定义。因此程序应改为:

max(x,y)

intx,y;

{intz;

第10章常见错误和程序调试·213·

z=x>y?x:y;

returnz;

}

(2)所调用的函数定义在调用语句之后,但在调用之前未加声明。如有:

main()

{floatx,y,z;

x=2.5;y=-5.6;

z=max(x,y);

printf("%fn",z);

}

floatmax(floatx,floaty)

{returnx>y?x:y;

}

编译时将出现error信息:

Typemismatchinredeclarationof'max'

原因是系统认为'max'类型不对。因为max函数是实型的,定义在main之后,但在main

函数调用此函数前时却没有声明,系统默认为是int类型的。C语言中,对被调函数定义在

主调函数之后的,除int类型的函数可以不用声明外,其它都要声明。纠正错误的方法有

两种:

①在main函数中增加对max函数的声明。

floatmax(floatx,floaty);

②把max函数的定义放到main函数之前。

(3)不要在函数的定义与函数的声明中混用新旧两种模式。如有:

main()

{floatfun(float,float);

}

floatfun(x,y)

floatx,y;

{…}

编译时将出现

Typemismatchinparameter

系统会认为函数max的参数类型不匹配。

(4)错误理解函数的参数传递。如有:

voidswap(intx,inty)

{intt;

t=x;x=y;y=t;

}

main()

·214·第10章常见错误和程序调试

{inta,b;

a=35;b=4;

swap(a,b);

printf("%d,%dn",a,b);

}

编译时并没有错误,但得不到预期的结果,因为main函数调用swap函数属于传值调

用,参数传递是单向的,形参的值发生变化是不会影响实参的,所以程序想通过调用swap

函数达到a和b交换的目的是实现不了的。

如果想使实参的值受到形参的影响,应该用数组名或指针变量作函数的参数,即用地

址传递的方式。这样形参的值在被调函数中发生的变化会影响到实参的值,如:

voidswap(int*pt1,int*pt2)

{intt;

t=*ptl;*ptl=*pt2;*pt2=t;

}

main()

{inta,b,*p1,*p2;

a=3;b=4;

pl=&a;p2=&b;

swap(p1,p2);

printf("%d,%dn",a,b);/*a和b的值已交换*/

}

但如果将swap函数定义成:

voidswap(int*pt1,int*pt2)

{int*p;

p=ptl;

ptl=pt2;

pt2=p;

}

同样也实现不了交换两个数据的目的。一定要理解函数间参数传递的实质,都是单向

的“值传递”。

(5)函数的实参和形参类型不一致。

main()

{inta=3,b=4,c;

c=fun(a,b);

}

fun(floatx,floaty)

{

第10章常见错误和程序调试·215·

}

编译时并无错误,但得不到正确的结果,因为实参a、b为整型,形参x、y为实型。

C要求实参与形参的类型、个数、顺序一致。

(6)混淆一般表达式与函数参数的计算次序。如有:

inti=5;

printf("%d,%d,%dn",i,++i,++i);

许多人认为输出必然是

5,6,7

其实不然。在TurboC系统中输出的是:

7,7,6

因为在该系统中,函数参数的计算次序是从右到左的。先求出最右面一个参数(++i)

的值为6,再求出第2个参数(++i)的值为7,最后求出最左面的参数(i)的值也是7。而一般

表达式的计算次序是从左到右的。如有:

i=3;

k=(i++)+(i++)+(i++);

不少人认为k的值为12即k=3+4+5,实际上k的值为9,因为系统先将i的值取出来

作为表达式的值进行加法运算3+3+3,然后再实现自加,即“先用后加”,最后i的值变为

6。

C语言没有具体规定函数参数求值的顺序是从左到右还是从自右到左。但每个C编译

程序都有自己的顺序,这就要求在使用中应当避免出现这种容易引起不同理解的用法,以

免使程序的通用性受到影响。如果在上例中,希望输出“5,6,7”时,可以改用

i=5;j=i+1;k=j+1;

printf("%d,%d,%dn",i,j,k);

(7)引用void类型的函数值。如有:

voidmax(intx,inty)

{returnx>y?x:y;

}

编译时出现error信息:

Typemismatchinredeclarationof'max'

因为函数的类型定义为void后,系统将禁止函数返回任何值。

5.指针类错误(Errorsofpointerclass)

(1)引用没有初始化的指针变量。如有:

int*p;

*p=10;

编译时将出现warning信息:

possibleuof'p'beforedefinition

原因是虽然定义了指针变量p,但是没有明确指针变量p的指向,直接引用可能会破

坏其它内存单元中的值,甚至造成系统破坏。可以改成:

int*p,a;

·216·第10章常见错误和程序调试

p=&a;

*p=10;

先将一个变量的地址赋给指针变量p,然后就可以对p进行操作了。

(2)混淆指针量与非指针量的区别。如有:

int*p;

p=100;

编译时将出现warning信息:

Non-portablepointerassignment

原因是系统认为程序将一非指针的量赋给一个指针量。因为指针变量只能存放地址,

不能将一个整型量(或非地址类型的数据)赋给一个指针变量。同样若将一个指针量给一

个非指针量时也会出现这样的警告。如:

inta,*p;

a=p;

(3)不同类型的指针混用。如有:

main()

{inti=3,*p1;

floata=1.5,*p2;

pl=&i;p2=&a;

p2=p1;

printf("%d,%dn",*p1,*p2);

}

编译时将出现warning信息:

Suspiciouspointerconversion

原因是系统认为程序中出现可疑的指针类型转换。因为在“p2=p1”中,p1、p2的基

类型不同,C不允许指针变量指向与它类型不同的数据。如果确实需要,必须进行强制类

型转换。应改成:

p2=(float*)pl;

这种情况在C程序中动态分配内存空间时是最常见的。例如,用malloc函数开辟内存

空间,malloc函数返回的是不指向任何类型数据的指针(void*),而人们希望开辟的是能

够存放一个结构体类型变量的值的存储空间。要得到指向该结构体类型变量的指针,必须

进行类型转换。如有:

#defineLENsizeof(structstudent)

structstudent

{intnum;

charname[20];

floatscore;

};

structstudent*p;

p=(structstudent*)ma11oc(LEN);

第10章常见错误和程序调试·217·

p是指向structstuden结构体类型数据的指针,将malloc函数返回的void*类型指针

转换成指向structstudent类型变量的指针。

(4)混淆数组名与指针变量的区别。如有:

main()

{inti,a[6];

for(i=0;i<6;i++)

scanf("%d",a++);

}

编译时将出现error信息:

Lvaluerequired

原因是系统认为a++进行了错误的赋值运算。虽然数组名代表数组的首地址,它是一

个不能改变的常量,当然不允许做a++运算。而指针变量则可以,应改为:

inti,a[6],*p;

p=a;

for(i=0;i<6;i++)

scanf("%d",p++);

int*p,a[6];

for(p=a;p

scanf("%d",p);

6.文件操作类(Erroroffileoperationclass)

使用文件时忘记打开或打开文件方式不对。如:

if((fp=fopen("test","r"))==NULL)

{printf("cannotopenthisfile\n");

exit(0);

}

ch=fgetc(fp);

while(ch!='#')

{ch=ch+4;

fputc(ch,fp);

ch=fgetc(fp);

}

对以“r”方式(只读方式)打开的文件,进行既读又写的操作,显然是错误的。

此外,有的程序常忘记关闭文件,虽然系统会自动关闭所用文件,但可能会丢失数据。

因此必须在用完文件后关闭它。

以上只是列举了一些初学者常出现的错误,这些错误大多是对于C语法不熟悉之故。

对C语言使用多了,比较熟练了,犯这些错误自然减少了。在深入使用C语言后,还会出

·218·第10章常见错误和程序调试

现其他一些更深入、更隐蔽的错误。

10.2程序调试(Programdebug)

所谓程序调试是指对程序的查错和排错。写完一个程序只能说完成了任务的一半(甚至

不到一半)。调试程序往往比写程序更难,更需要精力、时间和经验。有时一个小小的程序

会出错五六处,而发现和排除一个错误,有时竞需要半天,甚至更多。希望读者通过实践

掌握调试程序的方法和技术。

调试程序一般应经过以下几个步骤:

1.人工检查(静态检查)

在写好一个程序以后,不要匆匆忙忙上机,而应对纸面上的程序进行人工检查,这能

发现编写程序中的一些错误。为了更有效地进行人工检查,编写程序时应注意力求做到以

下几点:

(1)采用结构化程序方法编程,使程序结构清晰;

(2)尽可能多加注释,对每段程序及主要变量进行说明,增加程序可理解性;

(3)采用模块化结构,不要将全部语句都写在main函数中,要善于利用函数定义及

函数调用,用一个函数(模块)来实现一个单独的功能。这样既易于阅读也便于调试。

2.上机调试

通过上机发现错误称动态检查。在编译时给出语法错误的信息(包括哪一行有错以及错

误类型),可以根据提示的信息具体找出程序中出错之处并改正之。应当注意的是:有时提

示的出错行并不是真正出错的行,如果在提示出错的行上找不到错误的话,应当到上一行

再找。另外,有时提示出错的类型并非绝对准确,由于出错的情况繁多而且各种错误互有

关联,因此要善于分析,找出真正的错误,而不要只从字面意义上死抠出错信息,钻牛角

尖。

如果系统提示的出错信息多,应当从上到下逐一改正。有时显示出一大片出错信息往

往使人感到问题严重,无从下手。其实可能只有一二个错误。例如,若对一个变量未定义,

编译时就会对所有使用该变量的语句都发出出错信息。只要加上一个变量定义,所有错误

就都消除了。

3.分析程序运行结果

在改正语法错误(包括“错误”(error)和“警告”(warning))后,程序经过连接(1ink)就

得到可执行的目标程序。运行程序、输入程序所需数据,就可得到运行结果。应当对运行

结果进行分析,看它是否符合要求,为此要选择一些模拟数据进行测试。有的初学者看到

输出运行结果就认为没问题了,不作认真分析,这是危险的。

运行结果不对,大多属于逻辑错误,对这类错误往往需要仔细检查和分析才能发现。

可以采用以下办法:

(1)将程序与流程图仔细对照。如果流程图是正确的话,程序写错了,是很容易发

现的。例如,复合语句忘记写花括号。只要一对照流程图就能很快发现。

(2)如果实在找不到错误。可以采取分段检查的方法。在程序不同位置设几个printf

函数语句,输出有关变量的值,逐段住下检查直到找到在某一段中数据不对为止。这时就

已经把错误局限在这一段中了,不断缩小查错区,就可能发现错误所在。

第10章常见错误和程序调试·219·

(3)也可以用前面介绍过的“条件编译”命令进行程序调试。

(4)如果在程序中没有发现问题,就要检查流程图有无错误,即算法有无问题,如

有则改正之,接着修改程序。

(5)利用系统提供的调试工具,跟踪流程并给出相应信息,使用更为方便。

总之,程序调试是一项细致深入的工作,需要下功夫、动脑子、善于累积经验。希望

读者能给以足够的重视。

本文发布于:2023-02-02 02:13:00,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/88/175939.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

下一篇:浙江专科学校
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图