数学建模社区-数学中国

标题: [转帖]++C语言中常见错误++ [打印本页]

作者: solucky    时间: 2004-6-6 19:01
标题: [转帖]++C语言中常见错误++
<>C语言的最大特点是:功能强、使用方便灵活。C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。看着有错的程序,不知该如何改起,本人通过对C的学习,积累了一些C编程时常犯的错误,写给各位学员以供参考。
( {% H7 l7 A- i$ j1.书写标识符时,忽略了大小写字母的区别。
1 ]5 ?4 w# x" ?3 e# Q  }main()$ [' ]2 |  C2 j$ h% ^3 r( T
{; j: _! y  {4 L7 }  _) C4 M( N
int a=5;" Z# I" J6 U+ B8 d/ f
printf("%d",A);
9 v% x2 G( q& j' X9 F) f. X4 ]}
9 R1 p" {, Z6 b" c; }9 ?- N编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。6 h/ T2 l5 |& k2 t' t' ^( `
2.忽略了变量的类型,进行了不合法的运算。
  f4 `* Q* a3 ]main()
. Z  b7 K  n% B' m+ J{( X. B8 q2 A  A$ o% z
float a,b;
) h3 d: k  N/ k1 e7 a  hprintf("%d",a%b);
" [. U% A8 B5 z; g! y: x}
7 E2 @# H( t( x%是求余运算,得到a/b的整余数。整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。2 o3 Z  P+ R% A# o9 p# z
3.将字符常量与字符串常量混淆。- h9 \* l, {" ?
char c;- ]+ @8 F/ \6 C
c="a";
2 V! z+ K" E) C6 f在这里就混淆了字符常量与字符串常量,字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列。C规定以“\”作字符串结束标志,它是由系统自动加上的,所以字符串“a”实际上包含两个字符:‘a'和‘\',而把它赋给一个字符变量是不行的。
/ Q6 f9 S9 {/ j4 \* t4 I4.忽略了“=”与“==”的区别。
+ h7 `  L' {) G( X5 ]+ h在许多高级语言中,用“=”符号作为关系运算符“等于”。如在BASIC程序中可以写
0 @* @* E& k  D1 O/ Q$ t; X3 qif (a=3) then …8 v# l) n' e: A7 z) P
但C语言中,“=”是赋值运算符,“==”是关系运算符。如:
! |: D2 g- ^9 ?6 \% H" f5 F3 Vif (a==3) a=b;& r2 {- h7 n- c" v
前者是进行比较,a是否和3相等,后者表示如果a和3相等,把b值赋给a。由于习惯问题,初学者往往会犯这样的错误。
8 O3 N; n6 {7 c5.忘记加分号。2 p8 w$ o+ k  c1 I; Y
分号是C语句中不可缺少的一部分,语句末尾必须有分号。
9 r$ ~: C( C$ P3 q# v2 k* C7 W9 Ha=1
: |/ Y. {6 V' I; M9 B" ]b=24 h, S8 C0 p% ~6 k8 x
编译时,编译程序在“a=1”后面没发现分号,就把下一行“b=2”也作为上一行语句的一部分,这就会出现语法错误。改错时,有时在被指出有错的一行中未发现错误,就需要看一下上一行是否漏掉了分号。
" ]. L" l# c/ @1 A# P{ z=x+y;
2 I0 Y# O$ f0 ~* D) v* ot=z/100;
2 S, y  k3 r! j5 vprintf("%f",t);: B+ v  {+ ^: Q% F+ A
}5 p* e9 }- \4 L
对于复合语句来说,最后一个语句中最后的分号不能忽略不写(这是和PASCAL不同的)。
# c6 k5 _3 e5 N: j$ W  }& s6.多加分号。3 ^/ o" S2 u9 p! q& R% e
对于一个复合语句,如:( M. u3 V9 f  ~3 Y. b
{ z=x+y;
0 G* b! G$ k3 d# p  g# c1 ]t=z/100;
: L# k- a9 \; Q0 J: E- Oprintf("%f",t);
% [* M2 o5 K8 U};
2 ?7 w* j9 R& R+ _! N8 u复合语句的花括号后不应再加分号,否则将会画蛇添足。1 P! ~( D- Z5 o( C
又如:
( M, Z1 Y( F) q& b( cif (a%3==0);
8 k$ A5 D- Y' i+ Q" F  QI++;
" i* l2 ?+ l- I  B, B本是如果3整除a,则I加1。但由于if (a%3==0)后多加了分号,则if语句到此结束,程序将执行I++语句,不论3是否整除a,I都将自动加1。
5 T$ E1 D& v9 e# P4 t再如:  `7 I* ]; d9 T) }; W$ [) u# E
for (I=0;I&lt;5;I++);4 U) g8 Q) I9 s  N
{scanf("%d",&amp;x);" r: d& R" F; x' h, D4 x
printf("%d",x);}
+ S# J  x* F% ]7 X本意是先后输入5个数,每输入一个数后再将它输出。由于for()后多加了一个分号,使循环体变为空语句,此时只能输入一个数并输出它。/ z4 U: a# o3 T# F( ~* l3 A$ j3 E( g/ F
7.输入变量时忘记加地址运算符“&amp;”。
/ t3 c' [4 y9 J! tint a,b;
7 F9 z" i2 m4 h! H9 F5 hscanf("%d%d",a,b);% P/ Q, G  K  M' u
这是不合法的。Scanf函数的作用是:按照a、b在内存的地址将a、b的值存进去。“&amp;a”指a在内存中的地址。
) U/ r& T' M! h! ^4 M: T% Q7 {8.输入数据的方式与要求不符。①scanf("%d%d",&amp;a,&amp;b);8 a, A3 h  r7 o# [( c3 q& c& }2 w
输入时,不能用逗号作两个数据间的分隔符,如下面输入不合法:2 g. z; f/ T/ ?, ?; i" q6 Q
3,4 9 t  m( j" n' k& Q9 a) W7 v) |5 G
输入数据时,在两个数据之间以一个或多个空格间隔,也可用回车键,跳格键tab。
% B$ N4 ~  u1 N- z0 |②scanf("%d,%d",&amp;a,&amp;b);
, b3 q9 Z+ J& ^  `/ HC规定:如果在“格式控制”字符串中除了格式说明以外还有其它字符,则在输入数据时应输入与这些字符相同的字符。下面输入是合法的:
1 y& z, {/ L  s7 [" w/ n& Q0 ^+ m/ g3,4
4 `  ?" r( V8 e4 i此时不用逗号而用空格或其它字符是不对的。. p( K# @. O- t& q6 b: ~
3 4 3:4 % G' D0 i9 r& G5 J  o. Q
又如:  j) u' m& `. X2 S/ g  C
scanf("a=%d,b=%d",&amp;a,&amp;b);
' u% L5 {6 C6 D6 o8 r$ v输入应如以下形式:8 ~. a7 i6 C- s
a=3,b=4
& f& x5 |1 M. P( k+ D0 s9.输入字符的格式与要求不一致。
" g8 B  |$ x* {" {在用“%c”格式输入字符时,“空格字符”和“转义字符”都作为有效字符输入。$ C3 h: ]6 c% I7 \+ N4 D$ D
scanf("%c%c%c",&amp;c1,&amp;c2,&amp;c3);7 `8 j. h' Z0 l2 a, A+ n/ Q+ }
如输入a b c
+ U1 b9 F7 L& d" G# }" V8 D字符“a”送给c1,字符“ ”送给c2,字符“b”送给c3,因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔。
; q, h/ c6 D) V10.输入输出的数据类型与所用格式说明符不一致。
! d3 }( R" Y5 r" E4 p% F* P例如,a已定义为整型,b定义为实型* |8 n* k3 H# Q. i* d8 A& ?
a=3;b=4.5;0 u3 {1 i; O. j
printf("%f%d\n",a,b);
1 r6 y9 m' b) h0 m编译时不给出出错信息,但运行结果将与原意不符。这种错误尤其需要注意。
% @$ z# A: \! E$ P! G: c: d11.输入数据时,企图规定精度。; ]3 M* _* \4 D+ a5 ]6 M
scanf("%7.2f",&amp;a);  U0 c' W: F' S4 S. F
这样做是不合法的,输入数据时不能规定精度。* p2 f3 E" H2 I. G# p# u
12.switch语句中漏写break语句。
4 J: f! J$ }4 A9 z; j例如:根据考试成绩的等级打印出百分制数段。
4 i. _8 ~) F4 Tswitch(grade)5 M& y1 Q& u  g, }
{ case 'A':printf("85~100\n");  ?' S& d7 L( E: k- |' G* S* c
case 'B':printf("70~84\n");
1 k% |- k( ~% i7 [; f! dcase 'C':printf("60~69\n");
- L3 @' F8 Y8 y- N. l+ B( @case 'D':printf("&lt;60\n");% f4 P% L  \3 I* h# r. N
default:printf("error\n");0 c4 V3 q( B! _4 `
由于漏写了break语句,case只起标号的作用,而不起判断作用。因此,当grade值为A时,printf函数在执行完第一个语句后接着执行第二、三、四、五个printf函数语句。正确写法应在每个分支后再加上“break;”。例如
+ g/ X" x0 D/ [+ f6 `case 'A':printf("85~100\n");break;6 q" G; h& d( l( s+ o) S( R# d5 g' _
13.忽视了while和do-while语句在细节上的区别。8 l5 i3 v0 P! ]7 m/ E  k) p
(1)main()
$ q! K' q6 M6 J. a{int a=0,I;% }' }# G8 ?5 z2 ]$ B) t( P
scanf("%d",&amp;I);6 v" F+ d( o2 P! {' A
while(I&lt;=10)7 H- K1 j$ v( G7 M- J3 ^8 M  e# K
{a=a+I;
2 ~* X9 ?! V/ j2 [- _/ vI++;: y. C  t1 M( @( D, \: X
}
4 E+ T( t! w( V* e6 w$ v! g& eprintf("%d",a);
" M1 b' g7 ~. r! m1 k, p}
9 _2 W& r5 W2 c(2)main()
- ~) p  b6 _. u. a& I1 ^1 B) \  r) X5 R{int a=0,I;7 i( t( d' m8 e2 h9 C% l
scanf("%d",&amp;I);" \& O" J" D7 q7 M! W3 ]
do0 j9 b9 q+ R8 b
{a=a+I;- {5 Z, }9 U0 p
I++;
* S0 W7 z1 D" x( L" h; I9 u3 B$ t1 U}while(I&lt;=10);
. R8 k) C4 U# i/ V4 f4 mprintf("%d",a);9 w8 p4 y$ T9 d& `4 X& z2 P
}  q# ^  i6 P) ^3 ^: B; J
可以看到,当输入I的值小于或等于10时,二者得到的结果相同。而当I&gt;10时,二者结果就不同了。因为while循环是先判断后执行,而do-while循环是先执行后判断。对于大于10的数while循环一次也不执行循环体,而do-while语句则要执行一次循环体。. f) z) R  a! B7 G+ E5 W2 v  o
14.定义数组时误用变量。6 X; e. N4 A6 L* O6 k7 h! p4 M9 U
int n;
% w, Z6 A2 ?8 Xscanf("%d",&amp;n);
9 X/ a8 j6 L9 \1 oint a[n];8 Y' }- ?' V4 c3 F8 ]' f8 b
数组名后用方括号括起来的是常量表达式,可以包括常量和符号常量。即C不允许对数组的大小作动态定义。
3 a* M* m6 o4 h- i6 d4 E+ y15.在定义数组时,将定义的“元素个数”误认为是可使的最大下标值。
- {  i! z; s( @5 L4 cmain()
' V+ B3 h: d/ ~; I5 @# c! v5 _{static int a[10]={1,2,3,4,5,6,7,8,9,10};3 N0 {5 G5 m1 }2 a( E
printf("%d",a[10]);: O0 v& ^, ~3 D3 x4 a- L
}
. S7 b6 J9 I' S! w+ uC语言规定:定义时用a[10],表示a数组有10个元素。其下标值由0开始,所以数组元素a[10]是不存在的。, @  e4 H: \9 |
16.初始化数组时,未使用静态存储。/ P4 b' S1 H" v/ z5 y
int a[3]={0,1,2};
4 e* ?1 I) _' g8 V+ U8 n' V1 p" s4 D这样初始化数组是不对的。C语言规定只有静态存储(static)数组和外部存储(exterm)数组才能初始化。应改为:# a$ M8 Y* A- w
static int a[3]={0,1,2};8 g" F; ~. B3 L' [
17.在不应加地址运算符&amp;的位置加了地址运算符。4 |# m8 P0 A. c  H
scanf("%s",&amp;str);8 u: j' N3 t8 I% K0 f
C语言编译系统对数组名的处理是:数组名代表该数组的起始地址,且scanf函数中的输入项是字符数组名,不必要再加地址符&amp;。应改为:6 m7 x8 l3 g! i* e* h  b9 g8 U
scanf("%s",str);! t' W+ P( l2 x8 F2 u2 w: T3 z
18.同时定义了形参和函数中的局部变量。
3 o. S7 I/ R+ p: z' s9 ^. qint max(x,y)) n& m) N/ w1 k+ o0 x* E
int x,y,z;$ c; i; e/ `5 P5 }$ F. ~1 s9 r
{z=x&gt;y?x:y;5 S; ~. x+ E/ [, N; ]
return(z);( F2 c) |) E$ n+ M2 n; @
}, \% C) U% h' ~9 G7 R; b5 m: W( v# m; q
形参应该在函数体外定义,而局部变量应该在函数体内定义。应改为:
6 e1 i& Z. u. @7 @( Pint max(x,y)+ W. B+ Y8 w, ~" m
int x,y;5 `; f; ]2 ?5 W: a3 c
{int z;$ H2 D: g2 M* v0 _4 M4 R% c
z=x&gt;y?x:y;
! ?% {$ Z% O# @  r* ~/ S+ L  k" [1 areturn(z);  [. e" Z6 G) v+ A4 S# i
}</P>
5 h9 D/ I  _* o5 t# ]1 V<>以上错误中可能有些不符合新版的C语言,比如数组的初始化,新版中就可以是不是静态变量。由于是转贴就未加修改,以保持文章的原貌,请各位自加区别。<b>版权属于原创作者!!!</b></P>




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5