您好, 访客   登录/注册

C语言使用中的常见问题

来源:用户上传      作者: 张淑娟

  我们在C语言的学习和使用过程中经常犯一些小错误或者有很大的疑问,今天特把这些常见问题总结如下,以飨读者。
  
  1. 始化问题
  
  int a[100]={0};能否将数组中所有的元素初试化为零?
  答案是肯定的。因为在为数组初始化的时候,若作者提供的初始化元素个数小于数组长度,系统自动会将其余元素的值定为0。像例子中,初始化时作者只提供了一个元素0给了a,还有99个元素作者没有给出初始值。这时按照上面的规则系统会自动将剩余元素的初始值定为0。以此我们可以得到数组中所有元素初始化为0的结果。
  但我们不提倡这样的做法。一般初始化可以用for循环来实现。
  例:Int I,a[10];
  For(I=0;I<10;I++)
  Scanf("%d",a[I]);
  
  2. “文件包含”处理的两种形式的差异
  
  C语言提供了#include命令来实现“文件包含”的操作。
  其一般形式为:①#include"stdio.h"
  ②#include<stdio.h>
  程序运行的时候,①首先在用户当前目录中寻找要包含的文件,若找不到再按标准方式在相对路径下找stdio.h,找不到再到path里面找,而②系统到存放c库函数头文件所在的目录中寻找索要包含的文件,这是标准形式。
  一般说,若为调用库函数而用#include命令来包含相关的头文件,则用②形式以节省时间。若要包含的使用使用户自己编写的文件,一般用①形式。若文件不在当前目录中,①内可以给出文件路径。
  
  3. 宏使用问题
  
  宏替换一般在编译前,所以没有分配任何的空间,没有任何的类型可言,同时它是直接替换宏标号,所以使用一定要小心。例如:#definef(x)x*x
  main( )
  {int i;
  
  i= f(2+3);
  printf("%d\n",i);
   }
  输出结果是11而不是25,因为它只是简单替换,替换的结果是2+3×2+3,所以输出结果是11而不是25。
  有些人过分地喜欢用宏,其实宏的使用也不是越多越好,要防止代码的膨胀,现在的操作系统基本都是页式管理,当宏替换内容过大发生换页时,宏的效率不会比调用函数快,还好c++ inline解决了这个问题。
  
  4. 空函数
  
  void f();
   void f(void);
   void f(...);
  通常我理解的空有如下三种形式,它们的含义分别是:
  第一个函数的参数列表不是为空(C++里面是空),它的参数是不确定。
  第二个函数参数才为空。
  第三个函数是可变参数函数,很多库函数都是这样实现的,如:典型的printf(...)。
  
  5. C语言中的参数值的传递
  
  C语言里面只有值传递,即实参的值传给形参(单向传递)。那么有些人会问,那为什么用数组名或数组元素作函数参数的时候我们可以实现形参的值传递给实参呢?
  那是因为一般变量做函数参数时,形参在调用时系统要为他分配存储空间,实参与形参各自占用自己的存储空间,实参的值再复制给形参。数组名或数组元素作函数参数时,在进行存贮空间的分配时,不再为形参另外分配存储空间了,实参与形参共占用同一空间。其实它本质上也是值传递,即形参的值传给形参,只是传的实参的地址而不是参变量的值而已。
  
  6. 数组越界问题
  
  C语言为了追求最大的灵活和效率,不对数组进行边界检查,这些工作都是程序员自己的事情,不要以为你一越界编译器就会告诉你,只有当越界到编译器需要换页的时候才会报错。在理想情况下,Window下可以越界64K,不过很不幸,我试过很多次,最多达到了30k。不过这个数字也是很恐怖的,30k的汇编代码足以对你的操作系统做任何事情。
  7. 数组和指针
  首先必须要搞清楚一个问题,数组是数组,指针是指针,它们不是一回事。
  int a[100];
  int *p ;
  a数组名代表数组的地址值是个常量,它不能够被改变,而p是可以的。
  看看sizeof(a) = 100 和sizeof(p) = 4(vc6.0)
  对于字符串还要看看sizeof和strlen的区别:
  sizeof还是数组的大小,strlen以0结束(不包括0)。大家一定要注意,因为不注意出现问题,你都不知道怎么回事。
  如:
   void f( char * p )
  {
   if ( p == NULL )
   {
  return ;
   }
   char *t ;
   int lenOfP = strlen(p);
   t = ( char *) malloc( sizeof(char) * lenOfP );
   strcpy ( t , p ) ;
   .
   .
  }
  8. malloc 与free
  malloc free使用一般有几个原则:
  (1) malloc free必须配套使用,并且尽可能逆序。
  (2) 谁malloc的谁free。
  (3) 能够不动态分配的尽量不动态分配,动态分配是很费时间的,而且存在一定的风险。
  很多人喜欢这样写程序:
  type * f()
  {
  type *t = (type*)malloc ( sizeof(type));
  .
  .
  return t ;
  }
  这样肯定会出问题,一般像这种情况,一般声明f(type* t),谁调用它谁为t分配空间,谁来释放它的空间。不过很有意思的是,如char* asctime(),它返回一个表示时间的字符指针,但是并不要求你释放,你也没有办法释放,但是我可以肯定它这个串肯定不是在堆区分配的。
  free的顺序也很重要,很多时候free的时候会出现空指针的引用,不足为齐。有人提议free(t);t=NULL;这种用法有一定的道理,当你free一块空间后,操作系统不会立即回收,所以在你再次用t的时候可能还是可以用的,t就成了个野指针,而将其t=NULL后,对t的引用会出问题。


转载注明来源:https://www.xzbu.com/9/view-997506.htm