C语言的最大特点是:功能强、使用方便灵活。C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。看着有错的程序,不知该如何改起,本人通过对C的学习,积累了一些C编程时常犯的错误,写给各位学员以供参考。 - o1 e; Q4 C  h) q" T) c
  @1 ^7 d* x# C
  1.书写标识符时,忽略了大小写字母的区别。8 Z9 G- b# X0 u$ n3 x7 B
7 E! D6 n( J/ E) t4 s% e' Z5 X
main(); r- [) C9 U; c7 L. [8 b- Q
{% E$ V" U9 I8 W$ f! l
 int a=5;; [6 i8 W$ J/ b+ }1 q2 J
 printf("%d",A);( `3 p. x- j( I. a
}
7 s" K, Z5 t0 A! e  i& B6 H6 @  编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。
  [3 B" U2 j$ |6 G/ y
/ n; R# a! {% {5 }, [  2.忽略了变量的类型,进行了不合法的运算。5 c3 e# ~! b" n4 J3 |; U2 ^* D' d

% f( X; m! }6 amain(). l% H- M% m, R. n0 ?
{
6 u, ~* M* A+ T) }0 _2 ~! z/ ] float a,b;
1 S+ S' k, a7 d  b. N3 D printf("%d",a%b);
4 n' o5 z- S0 v' j) b}
3 P: d' ~1 \0 H  %是求余运算,得到a/b的整余数。整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。
9 q% A" L* L1 Z. d' q% g. q' r4 T- p! c/ |* |- g3 E
  3.将字符常量与字符串常量混淆。
4 ~  B0 Z7 }# @+ R6 n5 v  N- D4 A5 J
char c;  K- E4 U- n/ U- s( p0 g
c="a";
) H4 `# Z5 l7 _. ?9 ?6 a  在这里就混淆了字符常量与字符串常量,字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列。C规定以“\”作字符串结束标志,它是由系统自动加上的,所以字符串“a”实际上包含两个字符:‘a'和‘\',而把它赋给一个字符变量是不行的。: Z) O4 S2 r$ l

* p  I+ U3 t9 s' I  4.忽略了“=”与“==”的区别。; V4 @7 @8 ?. h" ?, e

$ b( s# y* m  G  在许多高级语言中,用“=”符号作为关系运算符“等于”。如在BASIC程序中可以写
  Q0 M% B! }9 Q" o
+ O! x7 N# [+ N" l, o  M, q7 ?if (a=3) then …
% n1 Q: Z: e8 {. y% O  但C语言中,“=”是赋值运算符,“==”是关系运算符。如:- e$ y' |: R: V+ V- O

. ^1 m7 X7 _: N* ~6 jif (a==3) a=b;0 {$ j* Y5 O8 {3 j) x
  前者是进行比较,a是否和3相等,后者表示如果a和3相等,把b值赋给a。由于习惯问题,初学者往往会犯这样的错误。
! W+ e( b  C0 P7 P  {/ e. g" H' ~$ b7 ]! L; D' Z- |* d9 k
  5.忘记加分号。( O9 c+ U1 ^- \3 A  u- D
/ U' b1 p$ p: h% }/ Z) O  ^
  分号是C语句中不可缺少的一部分,语句末尾必须有分号。9 ~7 \" ]: ?% ^& K

  b6 N  B( `3 x; T/ oa=1" j1 F  t6 v% _5 a, j% g6 T- D" @0 s
b=26 e, R: P! x. m" E" t; X9 d
  编译时,编译程序在“a=1”后面没发现分号,就把下一行“b=2”也作为上一行语句的一部分,这就会出现语法错误。改错时,有时在被指出有错的一行中未发现错误,就需要看一下上一行是否漏掉了分号。
' s: U  x. K8 w. {
0 ], ]& x$ u* U' u" ]+ I! p{
) h0 E; l6 p; Z# Q% Z z=x+y;! K$ u! f2 G& e
 t=z/100;3 X% H1 i# C2 E6 V$ z' X
 printf("%f",t);9 ]/ E9 B9 d* R' s6 U6 D5 [
}
. p0 y* i2 u+ W  对于复合语句来说,最后一个语句中最后的分号不能忽略不写(这是和PASCAL不同的)。, `/ k( v0 [8 ]: S) s* }4 r) Q

: n, l1 c6 x% b- {/ \  6.多加分号。
5 m0 H6 h  d  s( {) r. i9 l/ }" g6 p. d3 V0 D4 C1 h& G* P
  对于一个复合语句,如:
8 U8 z3 q( d) d6 Y( A
) L  ~, I9 l4 ]; H  t$ P{7 d1 |+ s6 c5 d9 B0 K- ~) S
 z=x+y;% w' f7 t! V5 s. n8 g$ S& t) l  }
 t=z/100;& `1 t1 C0 f, B" @2 y% I3 C8 m
 printf("%f",t);
4 x0 M1 _! |! d' G5 }};
  A! o. x+ I( Q4 s+ @  复合语句的花括号后不应再加分号,否则将会画蛇添足。
" |! l% x: z2 h* r' i7 R% }# @/ H( K4 X
  又如:7 L+ y% Y- N! {6 U/ y/ r
/ G8 t$ Z) W: O
if (a%3==0);
/ G2 y+ u- [/ Z) j; @I++;
: M0 q& p  B2 D& I# s  本是如果3整除a,则I加1。但由于if (a%3==0)后多加了分号,则if语句到此结束,程序将执行I++语句,不论3是否整除a,I都将自动加1。0 q' R0 c7 [% p6 \: B2 f" P
/ U/ P0 W. |1 g: f0 C5 m  O
  再如:* N/ k& K+ ?2 |+ G

; \( o. n3 u1 b0 g) p3 S# X2 Hfor (I=0;I
$ b3 f2 n) ?  h+ c9 H4 P
$ w+ w* J+ x, j  n# U) E  本意是先后输入5个数,每输入一个数后再将它输出。由于for()后多加了一个分号,使循环体变为空语句,此时只能输入一个数并输出它。) C. n9 G' c% G( |% @5 U, a3 i
7.输入变量时忘记加地址运算符“&”。
$ n/ |! g6 I' T3 h1 e1 c* h) j; Z" g1 Q
int a,b;$ j2 P1 b6 Z! v: R$ _- [* p* n
scanf("%d%d",a,b);5 M2 H* ]/ G* O5 P
  这是不合法的。Scanf函数的作用是:按照a、b在内存的地址将a、b的值存进去。“&a”指a在内存中的地址。0 j/ N; r1 Z( P6 x$ V! |
  j; b4 v" `; [  [
  8.输入数据的方式与要求不符。
- N+ t- L" k: V6 b, Q6 [
/ M1 P& R  C  |9 o  j4 |# Q" q4 \  ①scanf("%d%d",&a,&b);7 \& k, Y' M9 U& K: M

, _& e1 t( z; ?0 N8 k* F, |% x! \  t  输入时,不能用逗号作两个数据间的分隔符,如下面输入不合法:
; ^' ]/ J: |3 d; |, N+ u
2 ^$ v7 y/ V: G/ i% E7 L# @% A3,4 9 u8 X1 U; Z  C; z

; X, i. O, {' f( Z  输入数据时,在两个数据之间以一个或多个空格间隔,也可用回车键,跳格键tab。5 M3 _8 @3 _  y& z! h
0 P- ^5 i3 Q0 x& F2 p# p
  ②scanf("%d,%d",&a,&b);
+ R: ?! F/ {, {% Q, b. a
" J) v1 K  X* N% M  C规定:如果在“格式控制”字符串中除了格式说明以外还有其它字符,则在输入数据时应输入与这些字符相同的字符。下面输入是合法的:! `1 r3 H6 k1 d! P" s) a2 u& H0 M

  F0 k( I0 |& _9 Y0 X3,4
/ z, o3 {3 y: i0 s
; q; T9 ?/ E$ j  此时不用逗号而用空格或其它字符是不对的。
; F) N; o& y, n5 s
# H3 X0 |% u5 \5 d: f3 4 3:4
* q, S2 J6 H) J: e( b. R; _- x% ]; p3 t; M" O; y% U
  又如:- I' z+ K# h6 H% o
9 }, x; o' w6 X( ^+ _
scanf("a=%d,b=%d",&a,&b);2 M  Z9 G' y! P7 f
  输入应如以下形式:( H. K% c6 N! u

+ r; \  b5 ]( K: b( M% ya=3,b=4 # m) ?9 I: q1 Q; ]2 ]9 {' f: ~- Q
' S  w3 B# ^6 ?) c$ }
  9.输入字符的格式与要求不一致。
' I9 p' |4 _/ |$ h& z2 K2 N" Q! X) F2 p4 ^: o$ J0 R
  在用“%c”格式输入字符时,“空格字符”和“转义字符”都作为有效字符输入。
1 P" l' r: U3 f# B
1 _: }2 B" F( F  Escanf("%c%c%c",&c1,&c2,&c3);! P2 \# i5 E8 @/ W' Z6 Q
- Q/ T" S6 T2 g8 G) R
  如输入a b c 7 W" T" c) |! ~4 B- j& J7 S
4 c0 E5 Z, C- G
  字符“a”送给c1,字符“ ”送给c2,字符“b”送给c3,因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔。
& O: k# z/ C/ r) k" H# w& Z( `1 S# i/ y4 X7 _
  10.输入输出的数据类型与所用格式说明符不一致。6 Y& p3 h4 B% T. o& I

# C, |% l4 B# P+ P" e  例如,a已定义为整型,b定义为实型
" C! P: \/ h. F8 j; _/ ~! _7 A8 o
a=3;b=4.5;
% A2 Y0 I3 N  \$ u3 d2 j+ g; lprintf("%f%d\n",a,b);
$ j$ R. g' R+ ]" D5 l9 N5 b# K# H  编译时不给出出错信息,但运行结果将与原意不符。这种错误尤其需要注意。
6 D- k" O% O7 L* j0 {& k2 P* P
  11.输入数据时,企图规定精度。( d. T  {0 d4 I- Z. p* d6 Y
- I. u0 w& M9 G/ b) Q
scanf("%7.2f",&a);2 m* H8 k4 \( r! a0 e( }' [
  这样做是不合法的,输入数据时不能规定精度。
  K5 J2 l- i1 Z" R9 m& G  
1 m  p# w4 Q! C' X  12.switch语句中漏写break语句。; y8 r" z. D0 }0 g- O* ?

; f' x* s- c, z0 D* e  例如:根据考试成绩的等级打印出百分制数段。
2 E: j" W+ X2 g: O. h; L6 c" Q& \9 {- c7 M
switch(grade)
' D7 f5 ?: V* @- K+ i{
5 K, X, d/ C/ z# u! Q/ r case 'A':printf("85~100\n");
' ]& }, T' s9 j4 J4 Q case 'B':printf("70~84\n");3 ?- t$ R8 E, a; M6 J4 [
 case 'C':printf("60~69\n");# p. l. R, ~1 |% g& ~
 case 'D':printf("2 @' N  f3 o7 \4 j' k! C) X
  由于漏写了break语句,case只起标号的作用,而不起判断作用。因此,当grade值为A时,printf函数在执行完第一个语句后接着执行第二、三、四、五个printf函数语句。正确写法应在每个分支后再加上“break;”。例如8 Q# h1 U! G" S+ f+ K+ X2 [

  C5 t6 N3 t  _4 |/ Ucase 'A':printf("85~100\n");break;
9 V& U7 n/ n3 D5 o1 j& I& ^. r  13.忽视了while和do-while语句在细节上的区别。: ~' g1 f2 I/ q! g0 U0 ]

0 k/ ?& y6 ?& J! M6 J! w! }/ i  (1)main()
- N1 q( q  `8 i+ E3 f0 r
9 k* `; k9 r+ ~7 k{int a=0,I;
3 C: O, x2 z4 U/ J! ]& Iscanf("%d",&I);
6 ]2 D# v) m" h/ {: ]9 ^5 h4 q: mwhile(I# q7 N! w9 P/ k4 _: |9 _$ x0 p: R
  (2)
! N3 w+ w+ F; \% ^" `# x4 A& N
) _5 O  {5 q9 H2 ?5 wmain()
% E0 V" o7 S* {. R$ S1 P0 S: z
. Q# X. D1 g. y' N) B3 q& W' [: {# ]{int a=0,I;
' i+ D: v9 \# T: x4 [1 ?% iscanf("%d",&I);
5 ^3 o8 G5 R* s- a/ o) }$ cdo0 q8 K4 A0 F/ D1 B4 Y$ o1 {+ k, g
{a=a+I;4 F) w  @+ h9 D0 Y" u# z( s2 \4 F
I++;( h5 M0 `5 F$ E
}while(I* s) @9 i8 O2 \; N% S
  可以看到,当输入I的值小于或等于10时,二者得到的结果相同。而当I>10时,二者结果就不同了。因为while循环是先判断后执行,而do-while循环是先执行后判断。对于大于10的数while循环一次也不执行循环体,而do-while语句则要执行一次循环体。
7 j9 B* y2 H" c0 a6 E- |# ?
* G; {* w" p* t0 |' B  14.定义数组时误用变量。/ C" ~7 r$ Y9 z; R* W
" ]5 r& E( y: k( R
int n;) K8 q3 g0 l) `( c2 |
scanf("%d",&n);; b$ T* ^% T& z, [* e
int a[n];
$ K* A1 ^# S& M- `  数组名后用方括号括起来的是常量表达式,可以包括常量和符号常量。即C不允许对数组的大小作动态定义。0 U# y9 K: E2 n5 {7 K) M3 N9 `
 15.在定义数组时,将定义的“元素个数”误认为是可使的最大下标值。' Z5 S/ X- P9 g3 K$ W
5 ^( C, O2 b5 m- l1 Z
main()
" q5 J( N& W2 o3 c{static int a[10]={1,2,3,4,5,6,7,8,9,10};
; r' @) [4 k  c0 D! [; q7 F$ aprintf("%d",a[10]);
& s7 c* C7 N% h" J& H: x}
* f% N, Z: y8 s9 P8 G  C语言规定:定义时用a[10],表示a数组有10个元素。其下标值由0开始,所以数组元素a[10]是不存在的。- ]  r- J; f/ U* G

5 b  W1 i0 n& b. V) Y) B  16.初始化数组时,未使用静态存储。- f: N. T# _) u/ M" Y3 ^
; w5 a+ O+ n' e, h0 i! o
int a[3]={0,1,2};
# ?# z3 A- V- Y" {" Q  这样初始化数组是不对的。C语言规定只有静态存储(static)数组和外部存储(exterm)数组才能初始化。应改为:
) l" P- n" ^$ Z  I4 S% j
' W' |- R5 R+ N0 ^. X. Istatic int a[3]={0,1,2};: N5 F; p2 j" M5 A* `
  17.在不应加地址运算符&的位置加了地址运算符。
; ?; j! o  {$ Q: P: G( n: }6 M6 l! ~4 I! v: `5 f
scanf("%s",&str);, s8 r4 B& @" O% N
  C语言编译系统对数组名的处理是:数组名代表该数组的起始地址,且scanf函数中的输入项是字符数组名,不必要再加地址符&。应改为:* Y4 d& U) @! [  r" B

% S- p0 z9 S3 k  @* w- M0 |' [scanf("%s",str);
7 e. |/ c$ K6 P9 k$ \  18.同时定义了形参和函数中的局部变量。
7 w% I1 n. u5 J% }' b
! `8 E5 V- ^$ A7 p) Xint max(x,y)
- h. l* X8 A* A# Mint x,y,z;' {. y0 [0 m' W* c6 x6 U
{
8 g: Z( K( A. r z=x>y?x:y;4 t* \7 t# G. ]
 return(z);! ?  Q% H- s) N; h! ]7 Z
}  ~  t$ E" j; R
  形参应该在函数体外定义,而局部变量应该在函数体内定义。应改为:
6 K2 W( y# `( K  K/ `2 r4 r8 @' ]* c
int max(x,y): z% H+ a8 p1 Q
int x,y;- W9 l0 v; X; P* @+ Y& F: O
{  ?$ P; w" F3 e. O9 N6 b4 |
 int z;
* V! m2 n- d8 P4 X5 x z=x>y?x:y;' {* x+ |9 P& ]0 a: K' D
 return(z);" C! f* v! o. a/ W' E( E! D7 l6 m3 E
}