C语言陷阱 —— 数据问题
C语言中因为语言的特性或者因为开发人员编码的问题,总是存在各种各样让人欲仙欲死的陷阱,本文开始简单的对C语言的陷阱做一个小结。
数据引用错误
-
是否有引用的变量未赋值或者初始化
C语言中最常见的就是对未初始化的指针的引用。如:
int *p; *p = 3;
在这里因为只声明了指针,并没有对指针指向的区域做说明,这个时候指针p指向的空间是不明确的,因此,对一个未知的区域进行赋值,会产生非法内存访问错误。
-
数组的维度是否写死在代码里面
typedef ARR_NUM 100 int arr1[100]; int arr2[ARR_NUM]
数组长度的定义可以使用宏定义,因为宏定义在预处理阶段会进行替换,但是不可以使用const常量和变量作为数组的长度。(虽然作用域为函数内部的数组可以使用返回值为整数的函数返回值作为数组的长度,但是不推荐,作用域为全局的或者静态的局部数组不可以使用变量作为数组的长度,因为这两种变量在编阶段就会分配内存空间)。
-
数组下标是否在范围中
在C语言中数组下标越界往往是出现在循环判断的时候使用<=符号产生的。
-
对全局变量的检查
对全局变量等的修改要注意检查,修改之后是否会对其它模块产生影响。
-
宏定义使用未加括号
(1)定义宏定义的时候变量或者表达式没有加括号,宏替换的时候直接替出现问题,建议使用宏定义变量或者表达式的时候加上括号;
(2)在有++,–与?:运算符结合使用的地方,造成运算结果与预期的不一致。
-
在对内存的操作中注意字节序
数据声明错误
-
外部变量的声明与定义一致性问题
声明可以在多个地方使用相同的声明,即声明可以有多个,但是定义只能有一个,重复定义会造成内存访问覆盖等问题。
如int varb = 3; int varc = 4; int main() { float varb = 4.0; printf("%d\n", varc); return 0; }
如上例中,再次定义的varb有可能会覆盖掉原来的varb和varc的空间,造成最终的结果出乎意料。
-
数组和字符串的初始化为题
静态类型:如果没有手动初始化,在编译时自动初始化为0;
自动变量:运行时初始化;
注意区分字符串常量与字符数组,另外,注意指针与数组名不等价
-
注意变量是否赋予了正确的长度
数据类型 32位机 64位机 char 1 byte 1 byte short 2 byte 2 byte int 4 byte 4 byte long 4 byte 8 byte long long 8 byte 8 byte
运算问题
-
存在非算数变量之间的运算
在有指针的地方,引用指针指向的数据时,漏掉了*符号。
-
不同字长之间的运算
-
精度丢失问题
-
目标变量的类型小于赋值变量类型
-
除数为0
在除数是函数返回值的时候,或者除数是表达式的时候,记得考虑除数为0 的情况。
-
计算结果溢出
计算结果溢出,导致正数相加为负,正数相乘为负。
-
操作符优先级错误
操作符的优先级由高到低顺序如下所示:
前缀++ 前缀-- ()调用函数 []下标访问 {}组合文字 . -> (结合性从左到右)
后缀++ 后缀-- —负号 +正号 ~取反 sizeof *解引用 &取地址 (右结合性)
* / % (左结合)
+ - (左结合)
<< >> (左结合)
< > <= >= (左结合)
== != (左结合)
& (左结合)
^ (左结合)
| (左结合)
&& (左结合)
|| (左结合)
?: (右结合)
= += -= *= /= %= <<= >>= &= |= ^= (右结合)
,逗号运算符 (左结合)
-
检测乘法除法运算能否用位移代替
比较运算
-
比较运算的结果是整形值,而不是布尔值,在C中没有布尔值。
(1)相同符号,不同类型数据的比较:强制类型转换后再比较。
(2)有符号数与无符号数的比较:编译器自动将运算转化为无符号数的比较,所以C中严禁对不同符号的数进行比较。
(3)注意:C中不可以将无符号数作为while(num–)里面的num,因为无符号数在为0时,减1不是变成-1,而是变成0xffffffff
-
布尔表达式错误
误将&& || 用成了 & |
-
比较运算与布尔表达式混合了
-
操作符优先级错误
以上简单的列出了C语言中由于数据的问题产生的一些陷阱,在使用的过程中要谨慎一些,避免出现上述列表中的问题。