C程序常见错误30例

我们在学习C语言的过程中常常容易犯一些错误,下面就将一些错误列举出来,仅供参考:

1、忘记定义变量例如:

void main()
{
     x=3;
     y=6;
     printf("%d\n",x+y);
}
C要求对程序中用到的每一个变量都必须定义其类型,而上面程序中没有对 x,y进行定义。应该在函数的开头加:

int x,y;

2、输入输出的数据类型与所用格式说明符不一致。例如:

int a=3;
float b=4.5;
printf("%f %d\n",a,b);
对上面的程序,编译时不会出现错误,但是运行结果与意愿不符,输出为:

0.000000   16402

它们并不是按照赋值的规则进行转换(如把4.5转换成4),而是将数据在存在单元中的形式按照格式符的要求组织输出(如b占4个字节,只把最后两个字节中的数据按照%d作为整数输出)。

3、未注意int 数据的数值范围。Turbo C等编译系统,对一个整型数据分配2个字节。因此一个整数的范围为-2的15次方到2的15次方-1,即132768~32767。常见这样的程序段:

int num;
num=89101;
printf("%d\n",num);
得到的确实23565,原因是89101已超过32767,。2个字节容不下89101,则将高位截去,即将89101减去2的16次方,即89101-65536=23565。

4、在输入语句scanf中忘记使用变量的地址符,例如:

scanf("%d%d",a,b);
这是许多初学者常见的错误,或者说是习惯性的错误,因为在其他语句中只需要写出变量名即可。而C语言要求指明“向哪个地址标识的单元送值”。应写成

scanf("%d%d",&a,&b);
5、输入数据的形式与要求不符。用scanf 函数输入数据,应注意如何组织输入数据。假如有以下scanf 函数:

scanf("%d%d",&a,&b);
有人按下面的方法输入数据:

3,4↙

这是错误的。数据间应该用空格(或Tab 键,或者回车符)来分隔。

6、误把“=”作为“等于”运算符。在C语言中,“=”是赋值运算符,“==”才是关系运算符"等于"如果写成:

if(a=b)
   printf("a equal to b !");
C编译系统将(a=b)作为赋表达式处理,将b的值赋给a,然后判断a的值是否为零,若为非零,则作为“真”;若为零,则作为" 假"。

这种错误在编译时是检查不出来的,但运行结果往往是错误的。而且程序设计者自己往往也不容易发现。
7、语句后面漏分号。例如:

a=3
b=4.5
在编译时,编译程序在“a=3”后面未发现分号,就把下一行“b=4.5”也作为上一行的语句的一部分,这就出现语法错误。

8、在不该加分号的地方加了分号。例如:

if(a>b);
   printf("a  is larger than b !");
程序在运行到了if语句就结束了,接着执行下一条语句,即不论a 与b 的关系如何都会出现打印语句。
9、对应该有花括号的复合语句,忘记加花括号。例如:

<pre name="code" class="cpp">sun=0;
i=0;
while(i<=100)
     sum=sum+i;
      i++;

 上面的语句只是重复了sun=sum+i 的操作,而且循环永不终止。应该写成: 

sun=0;
i=0;
while(i<=100)
{
     sum=sum+i;
      i++;
}
10、括号不配对。当一个语句中使用多层括号时常出现这类错误,纯属粗心所致。例如:

while((c=getchar()!='#')
    putchar(c);
少了一个右括号。

11、在用标示符时,忘记了大写字母和小写字母的区别。例如:

void main()
{
      int a,b,c;
      a=2;b=3;
      C=A+B;
      printf("%d+%d=%d",A,B,C);
}
编译时出错。编译程序把a和A认作两个不同的变量名处理,是不同的变量。

12、引用数组元素时误用了圆括号。例如:

void main()
{
    int i,a[10];
    for(i=0;i<10;i++)
         scanf("%d",&a(i));
}

C语言中对数组的定义和引用都必须使用方括号。

13、在定义数组时,将定义的“元素个数”误认为是“可使用的最大下标值”。例如:

void main()
{
    int a[10]={1,2,3,4,5,6,7,8,9,10};
    int i;
    for(i=0;i<=10;i++)
         printf("%d",a[i]);
}
数组只包括a[0]到a[9]这10个数,因此用a[10]就超出a数组的范围了。

14、对二维或多维数组的定义或引用方法不对。例如:

<pre name="code" class="cpp">int main()
{
    int a[4,5];
       .
       .
    printf("%d",a[1+2,2+2]);
}

 上面程序中的a[4,5]应该改为a[4][5],a[1+2,2+2]应该改为a[1+2][2+2]。 

15、误以为数组名代表数组中的全部元素。例如:

int main()
{
    int a[4]={1,3,5,7};
    printf("%d %d %d %d",a);
}
企图用数组名代表全部元素。在C语言中,数组名代表数组首地址,不能通过数组名输出4个整数。

16、混淆字符数组和字符指针的区别。例如:

int main()
{ 
    char str[15];
    str="computer and c";
    printf("%s\n",str);
}
编译出错。str是数组名,代表这数组首地址。在编译时对str数组分配了一段内存单元,因此在程序运行期间str是一个常量,不能再被赋值。所以,str=" computer and c"是错误的。如果把“char str[15];" 改成“char *str;”则程序正确。此时,str是指向字符数据的指针变量,str=“ computer and c”是合法的,它将字符串的首地址赋给指针变量str,然后在printf 函数语句中输出字符串。

17、在指针变量之前没有对它赋予正确的值。例如:

int main()
{ 
    char *str;
    scanf(“%s”,str);
}
没有给指针变量赋值就引用它,编译时给出警告信息。应当改成:

char *str,c[20];
str=c;
scanf("%s",str);
先根据需要定义一个大小合适的字符数组c,然后将c数组的首地址赋给指针变量str ,此时str有确定的值,指向数组c。再执行scanf函数就没有问题了,把从键盘输入的字符串存放到字符数组c中。

18、switch语句中的各分支漏写break语句。例如:

switch(score)
{
  case 5:printf("Very good!");
  case 4:printf("Good!");
  case 3:printf("Pass!");
  case 2:printf("Fail!");
  default:printf("Data error!");
}
上述switch语句的作用是希望根据score(成绩)输出评语。但当score的值为5时,输出为:

Very good ! Good! Pass! Fail! Data error!

原因是漏写break语句。case只起标号的作用,而不起判断作用,因此在执行完第一个printf函数后接着执行第2、3、4、5个printf函数。应该为:

switch(score)
{
  case 5:printf("Very good!");
             break;
  case 4:printf("Good!");
             break;
  case 3:printf("Pass!");
             break;
  case 2:printf("Fail!");
             break;
  default:printf("Data error!");
             break;
}
19、混淆字符和字符串的表示形式。例如:

char sex;
sex="M";
   .
   .
   .
sex是字符变量,只能存放一个字符。而字符常量的形式是用单撇号括起来的,应该改为:

sex='M';
"M"是用双撇号括起来的字符串,它包括两个字符:’M‘ 、’\0‘,无法存放到字符变量sex中。
20、使用自加(++)和自减(--)运算符时出的错误。例如:

void main()
{
    int *p,a[5]={1,3,5,7,9};
    p=a;
    printf("%d",*p++);
}
不少人认为“*p++”的作用是先是p加1,即指向第一个元素a[1],然后输出第一元素a[1]的值 3.其实应该是先执行p++,而p++ 的作用是先用p 的原值,用完后使p加1,p的原值指向数组a的第0个元素a[0],因此,*p就是第0个元素a[0]的 值1。如果是*(p++),则先使p指向a[1],然后输出a[1]的值。

21、所调用的函数在调用语句之后才定义,而又在调用前未声明。例如:

void main()
{
   float x,y,z;
   x=3.5;y=4.5;
   z=max(x,y);
   printf("%f\n",z);
}
float max(float x,float y)
{
   return (x>y?x:y);
}
编译出错。max函数在main之后才定义,改错的方法可以用以下二值之一:

(1)在 main函数中增加一个队max函数的声明,即:

void main()
{
   float max(float x,float y);   //声明将要用到的max函数为实型
   float x,y,z;
   x=3.5;y=4.5;
   z=max(x,y);
   printf("%f\n",z);
}
float max(float x,float y)
{
   return (x>y?x:y);
}
(2)将max函数的定义位置调到main函数之前,即:

float max(float x,float y)
{
   return (x>y?x:y);
}
void main()
{
   float x,y,z;
   x=3.5;y=4.5;
   z=max(x,y);
   printf("%f\n",z);
}
这样,编译时不会出错,程序运行时也是正确的。

22、对函数声明与函数定义不匹配。例如:定义了一个fun 函数

int fun(int x,float y, long z);
在主调函数中作下面的声明都将出错。

fun(int x,float y, long z);         //漏写函数类型
float fun(int x,float y, long z);   //函数类型不匹配
int fun(int x,int y, long z);       //参数类型不匹配
int fun(int x,float y);             //参数数目不匹配
int fun(int x,long z,float y);      //参数顺序不匹配
下面的声明是正确的。

int fun(int x,float y, long z);
int fun(int ,float , long);        //可以不写形参名
int fun(int a,float b, long c);    //编译时不检查函数原型中的形参名
23、在需要加头文件时没有用# include命令去包含头文件。例如:

程序中要用到fabs函数,没有用 # include <math.h>

程序中用到输入输出函数,没有用 # include <stdio.h>

24、误认为形参值的改变会影响实参的值例如:

<pre name="code" class="cpp">
void main()
{
   void swap(int x,int y);   
   int a,b;
   a=3;b=4;
   swap(a,b);
   printf("%d %d\n",a,b);
}
void swap(int x,int y)
{
   int t;
   t=x;x=y;y=t;
}

 原意是通过调用swap函数使a 和 b的值对换,然后在main函数中输出已对换的值。但是这个程序打不到这样的目的,因为x和y的值的变化是不传回实参a 和 b 的,main 函数中的a 和 b的值并未改变。如果要达到这样的目的,应该使用指针变量,用指针变量作函数参数,使指针变量指向的变量的值发生变化。即: 

void main()
{
   void swap(int *x,int *y);   
   int a,b;
   a=3;b=4;
   swap(&a,&b);
   printf("%d %d\n",a,b);
}
void swap(int *x,int *y)
{
   int t;
   t=*x;*x=*y;*y=t;
}

25、函数的实参和形参类型不一致。例如:
void main()
{
   int fun(int x,int y);
   float a=3.5,b=4.6,c;
   c=fun(a,b);
    .....
    
}
int fun(int x,int y)
{
  return x+y;
}
实参a 、b为float型,形参x、y为int 型。C要求形参与实参的类型一致。程序在编译时给出“ 警告”信息,程序可以“带病运行”。

26、不同类型的指针混用。例如:
void main()
{
   int i=3,*p1;
   float a=1.5,*p2;
   p1=&i;p2=&a;
   p2=p1;
   printf("%d%d\n",*p1,*p2);
}
企图使p2也指向i,但p2是指向实型变量的指针,不能指向整型变量。指向不同类型的指针间的赋值必须进行强制类型转换。例如:

p2=(float  *)p1;

作用是先将p1的值转换成指向实型的指针,然后再赋给p2。

        这种情况在C程序中是常见的。例如,用malloc函数开辟内存单元,函数返回的是指向被分配内存空间的void *l类型的指针。而人们希望开辟的是存放一个结构体变量值的存储单元,要求得到指向该结构体变量的指针,可以进行如下所示的类型转换。

struct student
{
  int num;
  char name[10];
  float score;
};

struct student stdent1,*p;
   .....
p=(struct student *)malloc(sizeof(struct student));
 p是指向 struct student 结构体类型数据的指针,将malloc函数返回的 void *类型指针转换成指向 struct student 类型变量的指针。

27、没有注意函数参数的求值顺序。例如:

int i=3;
printf("%d,%d,%d",i,++i,++i);
许多人认为输出必然是:

3,4,5

实际不尽然,在Turbo C、Visual C++和其他一些C系统中输出的是:

5,5,4

因为这些系统采用的自右向左的顺序求函数参数的值。

28、混淆数组名和指针变量的区别。例如:

void main()
{ 
   int i,a[5];
   for(i=0;i<5;i++)
   {
       scanf("%d",a++);
   }
}
企图通过a的改变使指针下移,每次指向欲输出数据的数组元素。错误在于不了解数组名代表函数的首地址,它的值是不能改变的,用a++是错误的,应该用指针变量来实现,即:

void main()
{ 
   int i,a[5],*p;
   p=a;
   for(i=0;i<5;i++)
   {
       scanf("%d",p++);
   }
}
或者:
void main()
{ 
   int a[5],*p;
   for(p=a;p<a+5;p++)
   {
       scanf("%d",p);
   }
}
29、混淆结构体类型与结构体变量的区别,对一个结构体类型赋值。例如:

struct worker
{
    long int num; 
    char name[20];
    char sex;
    int age;
};
worker.num=10101;
strcopy(worker.name,"ZhangFun");
worker.sex='M';
worker.age=20;
这是错误的,只能对变量赋值而不能对类型赋值。上面只定义了struct  worker类型而未定义变量。应该改为:

struct worker
{
    long int num; 
    char name[20];
    char sex;
    int age;
};
struct worker  worker_1;
worker_1num=10101;
strcopy(worker_1.name,"ZhangFun");
worker_1.sex='M';
worker_1.age=20;
定义一个结构体变量,并对其中的各个成员赋值。

30、使用文件时忘记打开或者打开方式与使用情况不匹配。例如,对文件的读写,用只读的方式打开,却企图向该文件输出数据,例如:

if((fp=fopen("test.txt","r")==NULL)
{
    printf("cannot open this file!\n");
     exit(0);
}
ch=fgetc(fp);
while(ch!='#')
{
  ch=ch+4;
  fputc(ch,fp);
  ch=fget(fp);
}
对以“r”(只读方式)方式打开的文件,进行既读又写的操作,显示是不行的。

此外,有的程序常忘记关闭文件,虽然系统会自动关闭所有文件,但是可能会丢失数据。因此必须在用完文件后关闭它。


以上只是列举了一些初学者常出现的错误,对这些错误大多是对于C语法不熟悉所造成的。对C 语言使用多了,比较熟练了,犯这些错误自然就会减少。在深入使用C语言后,还会出现一些更深入、更隐蔽的错误。

总结之:程序出错有3中情况:

(1)语法错误。违背了C语法的规定,对这类错误,编译系统一般能给出“出错信息”,并且告诉在哪一行出错。只要细心,就会很快发现并排除的。

(2)逻辑出错。程序并无违背C语法规定,但程序执行的结果与原意不符。这是由于程序设计人员设计的算法有错误或者变成的程序有错,通知给系统的指令与解题的原意不符,即出现了逻辑上的错误。

(3)运行错误。程序既无语法错误,也无逻辑错误,但在运行时出现错误甚至停止运行,例如:

int a,b c;
scanf("%d%d",&a,&b);
c=b/a;
printf("c=%d\n",c);
输入a 和 b的值,输出b/a的值,程序没有错。但是如果输入a 的值为0,就会出现错误。


写完一个程序只能说完成任务的一半(甚至不到一半)。调试程序往往比写程序更难,更需要精力、时间和经验。

















  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值