C语言初学者编程的常见错误及分析

2013-07-17 01:54马晓娟
赤峰学院学报·自然科学版 2013年18期
关键词:程序段语法错误数组

马晓娟

(集宁师范学院计算机系,内蒙古乌兰察布012000)

C语言初学者编程的常见错误及分析

马晓娟

(集宁师范学院计算机系,内蒙古乌兰察布012000)

C语言最大的特点是功能强大、使用方便灵活.C语言的编译程序对语法检查并不象其它高级语言那么严格,某些错误编译程序不予以检查,这不但给编程人员留下灵活的空间,而且给调试程序带来许多不便,尤其对于初学者来说,经常会出现一些莫名其妙的错误.要想快速排错除了学习时严格掌握C的语法规则,还要经常归纳总结,这样就可以避免一些典型错误的发生.

语法错误;编译;逻辑错误

1 引言

作为一个长期从事C语言教学的教师来说,经过多次的教学过程,发现初次接触C语言的相当一部分同学入门比较慢,往往跟不上老师的节奏,导致知识讲授越多问题堆积越多,编程错误越多.编程语言的语法规则是很严格的,即使出现一丝错误也使得整个程序不能运行或运行出错误的结果,这就要求教师在讲课时突出强调语法格式与种种注意事项.

编程错误分两种,语法错误与逻辑错误.语法错误是违背语句语法规则表现的错误,这种错误编译程序在编译时能检测出来,并给出用户错误提示信息,用户可参考这些信息修改错误直到没有编译错误.但是没有语法错误并不能保证程序一定是正确的,有可能会运行出错误的结果,这就说明程序有逻辑错误,指的是程序的算法有问题,算法在逻辑上与题目要求不符.逻辑错误要比语法错误难排除,往往要求用户有很扎实的基础.

经过多次教学经验的积累,不难总结出一些初学者编程中会出现的普遍性错误,其中包括了各种语法错误与逻辑错误,以下将对其分类逐一的分析.

2 初学者编程时的常见错误及分析

2.1 关于变量定义、赋值、引用的错误

2.1.1 书写标识符时,忽略了大小写字母的区别.如:

编译程序区分大小写字母,把a和A认为是两个不同的变量名,从而显示变量A未定义这一错误提示信息.

2.1.2 将字符常量与字符串常量混淆.如:

字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列.C规定以’’作字符串结束标志,它是由系统自动加上的,字符串“a”实际上包含两个字符:’a’和’’,所以不能把它赋给一个字符变量.

2.1.3 变量没有赋值就直接使用,变量的值实际上是随机值.如:

x没有固定的初值就进行条件判定导致其条件成立与否也是随机的.尤其在引用数组元素时其下标变量若是此种情况,则可能引用非法数组元素.如:

第二条语句中的变量i未被赋值,其值不确定,极有可能超出下标范围0—2,也就是说所引用的数组元素a[i]极有可能不是数组a的元素.

2.1.4 变量赋值超出其数据类型范围.如:

在Turbo C运行环境中,int型变量占内存2个字节,且其最高位是符号位,表示数的范围是-32768—32767,若变量值超出此范围,则数据会发生变化.上例中的输出结果为-1,实际是将65535的二进制值(16位全1)看做带符号数转换成10进制的-1输出.如需赋值为65535,可以将变量定义为long型.

2.1.5 用变量定义数组长度.如:

说明数组长度的只能是常量表达式,而不能出现变量,即C不允许对数组的大小作动态定义[1]. 2.1.6将数组定义时的“元素个数”误认为是可使用的最大下标值[2].如:

定义时用a[10],表示a数组有10个元素.其下标值从0到9,所以a[10]是不合法的数组元素,它其实表示数组最后一个元素的下一个单元的值.这种下标越界错误编译程序不予检测,所以一旦犯了就很难发现.

2.1.7 交换变量值时所用的中间变量与被交换变量类型不一致.如:

很多同学习惯将中间变量t定义为整型,而x与y是结构体类型,类型不同不能赋值.

2.2 关于输入输出的错误

2.2.1 输入变量时忘记加地址运算符.如:

scanf函数的作用是:按照a、b在内存的地址将a、b的值存进去.“&a”指a在内存中的地址.所有变量用scanf函数输入值时都需要加“&”,但字符数组除外,因为数组名本身就代表了数组的起始地址[3].如下程序段是正确的:

2.2.2 输入数据的方式与要求不符.如:

输入时,不能用逗号作为两个数据间的分隔符,应在两个数据之间以一个或多个空格间隔,也可用回车键或跳格键tab.如果在格式控制字符串中除了格式说明以外还有其它字符,则在输入数据时应输入与这些字符相同的字符.若输入函数写为scanf("%d,%d",&a,&b);则应输入:3,4,此时不用逗号而用空格或其它字符作为分隔符是不对的.又如:scanf("a=%d,b=%d",&a,&b);应输入:a=3,b=4. 2.2.3使用格式输入函数时格式字符串末尾加“ ”.如:

输入时敲3,4后再敲回车无法结束输入,必须敲入“3,4 ”才可以正确将两数存放到对应的变量里面,这就是末尾加了“ ”的副作用.

2.2.4 输入输出的数据类型与所用格式字符不一致.如:

编译时不给出出错信息,但实型数据用%d输出结果为0,整型数据用%f无法输出.这种错误尤其需要注意.

2.2.5 输出时将输出数据也放到格式字符串中.如:

函数调用语句没有语法错误,编译程序将其理解为输出两个整型随机数,因为没有输出数据只有格式字符串,本应该作为输出变量的a,b被看做普通字符原样输出.

2.3 关于各种运算的错误

2.3.1 忽略了变量的类型,进行了不合法的运算.如:只有两个整型数据才能进行求余运算,而实型数据不可以.

2.3.2 忽略了“=”与“==”的区别,在比较两个量相等时用了“=”[4].

在C语言中,“=”是赋值运算符,“==”是关系运算符.如if(a==3)a=b;表示如果a和3相等,把b值赋给a.但若写成if(a=3)a=b;则表示将3赋值给a,而条件a=3为真值,所以执行语句a=b;

2.3.3 将数学中的关系式应用到程序中.如:

其中条件是错误的表达式,要表示x是一个一位数只能写成x>0&&x<=9,即变量只能和一个量进行关系运算.

2.3.4 使用逗号表示若干条件同时成立.如:

括号中的条件可以被编译程序理解为一个逗号表达式,而其值是由后面的x<=9决定的,相当于x>0不起作用,从而也就不能表示两个条件同时成立.

2.3.5 表示复杂表达式时圆括号个数不一致.如:

这是一个计算一元二次方程根的赋值语句,括号比较多,极容易丢掉括号,写完语句应数一下左右括号的数目,或应仔细检查表达式的书写情况.

2.4 关于基本语法规则的错误

2.4.1 语句尾部忘记加分号.

分号是C语句中不可缺少的一部分,语句末尾若没有分号,编译程序将把下一行也作为上一行语句的一部分,这就会出现语法错误.改错时,有时在被指出有错的一行中未发现错误,就需要看上一行是否缺分号.

2.4.2 多加分号.如:

本意是如果a为3的倍数则i加1.但由于if (a%3==0)后多加了分号,分号代表空语句,此语句将被理解为如果a是3的倍数则执行空语句,而后面的i++;不受条件的限制,程序将无条件执行语句“i++;”,不论3是否整除a,i都将自动加1.再如:

本意是输入5个数,每输入一个数后将其累加到s.由于for()后多加了一个分号,使循环体变为空语句,此时只能输入一个数并将其加到s.

2.4.3 当条件成立时执行多条语句,但这些语句没有加花括号构成复合语句.如:

以上程序段是用来计算三角形面积的,在能构成三角形时计算周长的一半、跟着计算面积并输出面积,所以条件成立时执行后面三条语句,应将三条语句括起来构成复合语句.若不加括号,则理解为条件成立时求周长的一半(即单分支if语句),后面的计算并输出面积是无条件执行的,紧跟着出现的else就是非法的,没有与之配对的if.

2.4.4 使用for语句时for后面的括号中出现多于两个分号.如:

计算1*5+2*4+3*3可用以下语句完成:

很多学生都不遵守语法规则,每出现一个表达式就跟一个分号,写成:

2.4.5 循环体为多条语句但未加花括号.如:

虽然将s+=i;和i++;写在同一行上,但循环体仅仅是跟在while后面的一条语句,所以只有s+=i;是循环体,而i的值在循环中一直都没有改变,所以条件总是成立的,循环将一直进行下去,这就形成了死循环.应将i++;也归到循环体中程序段就可以求出1到10的累加和,当多条语句充当循环体时要加花括号将其构成复合语句,这种错误是循环程序中的常见错误.

2.4.6 在if语句或循环语句中缺花括号.如:

在if子句中包含三条语句,加括号时只在前面写了一半,后一半括号丢掉了.又如:

上述程序段是求半径1到10且周长小于40的圆的面积,在循环体结束处缺一半花括号.

2.4.7 使用库函数但没有包括其所在文件.

如果在程序中用到sqrt或fabs函数,应在程序首部包括其所在的库文件math.h,如果没有这个文件包含命令,则编译程序不识别被调用的库函数.

2.5 关于数组应用的错误

2.5.1 字符数组不能整体赋值.

a、b都是字符数组,如果要将a中存放的串赋给b,使用b=a;是错误的,因为数组名代表数组的起始地址,这样做是要改变数组的起始地址,显然是不允许的,只能用strcpy(a,b);来完成.

2.5.2 直接使用关系运算符实现字符串的比较.如:

以上程序段预将a、b中较大的串拷贝到m,但串不能直接比较,否则比的就是两个数组的起始地址,只能用串比较函数.要表示a大于b应使用表达式strcmp(a,b)>0.

2.6 关于函数应用的错误

2.6.1 函数定义中缺花括号.如:

常常会有人将循环结束的括号看作是函数结束的括号,而将函数最后的括号丢掉.

2.6.2 函数定义时函数首部末尾加分号.

很多初学者教条地认为每一行尾部都要有分号,教师要特别注意强调函数首部、文件包含与符号常量以及宏定义尾部没有分号.

2.7 关于指针应用的错误

2.7.1 指针没有具体指向就直接使用.如:

引用指针时必须保证指针指向某个变量,如果没有明确指向就直接引用,则有可能改变很重要的内存单元的值.

2.7.2 基类型不一致的两个指针变量互相赋值.如:

基类型不一致的指针变量不能直接赋值,应在赋值前将右值强制类型转换到左值的类型,上述程序段最后一条语句应改为p=(int*)q;.

2.8 典型的逻辑错误

2.8.1 循环控制变量书写有误.如:

上述程序段本来是用来输入二维数组元素值的,但在内层循环语句中误将j=0输入成i=0,这样造成变量j没有赋初值就直接使用,其值为随机值,极有可能内层循环1次也不执行,元素a[i][j]也极有可能是非法的,并且当i取1时,进入到内层又将其值置为0,执行完i++;增1后变为1,如此循环往复不能停止,这样的一个笔误无形中就构成了死循环,这种错误很难发现.

2.8.2 由两个循环变量控制的循环写成双层循环结构.如:

计算1*5+2*4+3*3可用以下语句完成:

一些初学者会将其写成两个变量各自控制一层的双循环,常常写成如下语句:

显然两种做法在逻辑上的功能有重大的差别.

2.8.3 变量交换时语句的次序问题以及变量出现的次序问题

在程序中常常要交换变量的值,但这也是易犯错误的环节,如使用t交换x和y的值,可能出现以下几种错误的做法:

3 小结

文章列举了一些典型错误的表现形式并分析了出错原因,进一步强调了很多容易让人忽视的语法规则和常见问题,对初学C语言的入门者有一定的指导作用,对于初学者培养良好的编程习惯有一定的帮助.在进一步学习和应用C语言的过程中,还会遇到更多更隐蔽的错误,所以更清晰地分析程序的结构、扎实掌握好每一个知识点对调试程序排除错误将大有益处.

〔1〕霍顿.C语言入门经典[M].北京:清华大学出版社,2008.

〔2〕Andrew Koenig.C陷阱与缺陷[M].北京:人民邮电出版社,2002.

〔3〕牛雅莉,赵芳林.C语言中常见逻辑错误分析[J].北京工业职业技术学院学报,2008(2).

〔4〕C语言编程常见问题解答[M].北京:清华大学出版社,1996.

TP312

A

1673-260X(2013)09-0016-04

变量一定要保证其值固定,而上例中的a和b都没有初值.又如:

猜你喜欢
程序段语法错误数组
基于WinCC的物料小车控制系统设计与仿真
JAVA稀疏矩阵算法
JAVA玩转数学之二维数组排序
数控系统手轮回退功能的研究与实现*
基于NC程序段的提高数控加工监控阈值与信号同步的方法*
数控铣床FANUC 0i 系统刀具半径补偿系统参数设置解析
Excel数组公式在林业多条件求和中的应用
汉语负迁移对英语写作的影响及启示
高中英语写作中的语法错误分析
寻找勾股数组的历程