C陷阱篇之常见手误

    C的某些语法容易让人不小心触雷,比如

0开始的下标

    很多高级语言中,定义n个元素的数组,下标范围是从1n,但C特殊,n元素的C数组中没有下标为n的元素,只有从0n-1的下标。所以使用C数组时不要犯这种错误:

int i, a[10];

for ( i = 1; i <= 10 ; i++ ) {  a[i] = 0;  }   //i=10时超出数组边界

八进制or十进制常数

    C编译器会把数字025当作八进制,等于十进制的21,因此在使用常整数时不要认为多个0无关紧要,特别在从其他文件或标准中拷贝一些常系数数组时,要留意预防。

未初始化变量

    变量未初始化往往带来很难查找的随机错误,下面是开发中真实的例子:

    typedef struct tag_PARM{      //结构体定义

      char* Clip;

      bool InitParsingEnable;

      ……

      bool IsHttpStream;

    }PARM;

    /*结构体初始化*/

    PARM spliterParm;

    spliterParm.Clip = &iFilename;

    spliterParm.InitParsingEnable = iParsingMode;

    /*调用*/

    res = Open(&spliterParm);

    IsHttpStream是后期添加的一个成员变量,初始化部分忘记给它赋值,而在open函数里有:if(pParm->IsHttpStream)    ……else    ……

    这就导致Open随机执行到不同分支。变量未初始化的主要表现就是多次运行同样程序,随机错误。未初始化的问题很常见,特别是结构体,其定义和初始化不象普通局部变量那样相距很近,所以头文件里成员变量改变后很容易遗漏对应的初始化。

浮点数比较和交换

    void main()

    {

      float x =1.2; float y = 3.2;

      if((x + y)==4.4)  {  printf(“correct\n”);  }

      else  {  printf(“ error \n”);  }

    }

    结果是error。浮点数是为了能用二进制表达小数而引入的一种量化形式,转换时存在舍入误差,因此不能直接用==比较浮点数。正确做法是确定一个误差范围,通过比较两浮点数差值是否落在这个误差范围内来判定是否相等,即:

    const float delta = 0.1

    void main()

    {

      float x =1.2;  float y = 3.2;

      float z = x + y;

      if((z < (4.4+delta))&&(z > (4.4-delta))) {  printf(“correct\n”);  }

      else  {  printf(“ error \n”);  }

    }

    同样,由于浮点数有舍入误差,也不满足交换定律,如浮点数float x=1/3,y=1/6,z=1/7; 和整数不同,x*y/z不等于x*(y/z)

字符串结尾的隐含结束符导致内存越界

    char *r = malloc(strlen(s) + strlen(t));

    strcpy(r, s);

    strcat(r, t);

    以上实现忘记了字符串结尾隐含的空字符,strlen()返回字符串里真正的字符数,但不包括结尾的空字符。因此如果strlen(s)n,则s需要n+1个字节空间存储。即:

    char *r = malloc(strlen(s) + strlen(t) + 1);

    strcpy(r, s);

    strcat(r, t);

log语句中的有效操作

    有人认为printf/log/trace等打印函数的唯一功能就是输出调式信息,因而随意对待它们,但是printf等函数里也能包含有效操作,如:

    int a[5]={6, 7, 8, 9, 10};

    int *ptr = a;

    printf(%d, *(++ptr));

    *(ptr++) += 123;

    单纯把printf看做log语句,修改程序时就可能随手注释掉(printf开开关关经常发生),而printf内的有效操作也同时被删除,类似情形还包括printf内的函数调用等。因此最好把printf和有效操作放在两条语句,否则是自己挖坑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值