当前位置:首页 > c陷阱与缺陷学习笔记
#include
int main (void) {
char s[10]; char t[10];
char *r;
char *malloc();
r = malloc(strlen(s) + strlen(t) + 1); if(!r) {
complain(); exit(1); }
scanf(\ /*getchar();*/
scanf(\
strcpy(r,s); strcat(r,t);
printf(\ free(r); }
3.3 作为参数的数组声明
我们没有办法将一个数组作为函数参数直接传递。数组名会被转为指向该数组第一个元素的指针。
int strlen(char s[]){} 与下面的写法完全相同: int strlen(char* s){}
但其它地方就未必相同了。 下面两 个语句是完全不同的。 extern char *hello; extern char hello[];
下面则是一样的
main(int argc, char* argv[]){} main(int argc, char** argv){}
3.4 避免“举隅法”
复制指针并不同时复制指针所指向的数据。
3.5 空指针并非空字符串
把常数0转为指针,则指针不等于任何有效的指针,即 void 指针。其它将整数转为指针得到的结果未定
义。当常数0被转为指针时,这个指针绝对不能被解除引用(dereferenc)。换句话说,当我们将0赋给一个指
针变量时,绝对不能企图使用该指针所指向的内存中存储的内容。
下面的是合法的: if (p == (char *) 0) 但下面是非法的
if (strcmp(p, (char *) 0) == 0)
如果p是一个空指针,即使printf(p);和printf(\的行为也是未定义的。
3.6 边界计算与不对称边界
数组的下标如果用入界口加出界口来表达(即10个元素,其下标为0 <= n < 10 ),则元素个数即为上界与下界
之差,即下界。若为空,则上界等于下界。任何情况下上界也永远不可能小于下界。
尽量采用非对称边界法。
一个有N个元素的数组 ,我们可以使用a[N]进行比较和赋值,但不能引用其内容。
3.7 求值顺序
C语言只有四个运算符(&&, ||, ?: , 和 ,)存在规定的求值顺序。另外,分隔函数参数的逗号并非逗号
运算符。例如,在x和y在函数f(x,y)中的求值顺序是未定义的,而在函数g((x,y))是先算x,再算y,y
的值为参数。特别是赋值运算符没有规定求值顺序。
3.9 整数溢出
无符号算术运算中,没有所谓的“溢出”一说。有符号运算中发生溢出,则结果未定义。
下面检测溢出的方法不可靠: if(a + b <0) complain();
应该这样:
if((unsigned) a + (unsigned) b >INT_MAX) complain();
或者这样
if(a > INT_MAX - b) complain();
3.10 为函数main提供返回值
如果没 有为函数声明返回类型,则默认为int.
free之后最好马上就p = NULL;
Chapter 4 连接
4.1 什么是连接器
连接器通常把目标模块看成是由一组外部对象组成的。 第个外部对象都代表着机器内存中的某个部分,并
通达一个外部名称来识别。因此, 程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个 外部对象。 某些编译器会对静态函数和静态变量的名称做一定改变,将它们也作为外部对象。
除了外部对象,目标模块还可能包括了对其它模块中的外部对象的引用。
4.2 声明与定义
每个外部变量只能定义一次。
4.3 命名冲突与static修饰符
4.4 形参、实参与返回值
每个函数都要在调用之前进行声明定义,不然返回类型为int
如果一个函数没有float,short或者char类型的参数,在函数声明中完全可以省略类型声明(定义不能省 略)
4.5 检查外部类型
同一个外部变量在不同的地方被声明为不同的类型,这种错误大部分编译器是检不出来的。
char file[]= \ 与
extern char* file; 是不一样的。
4.6 头文件
Chapter 5 库函数
C标准没有定义执行底层I/O操作的read和write函数。 5.1 返回整数的getchar函数
5.2 更新顺序文件
为了与以前的程序保持兼容,一个输入操作不能随后紧跟一个输出操作,反之亦然。如果要同时进行输入
和输出操作,必须在其中插入fseek函数的调用。
FILE *fp;
struct record rec;
while (fread((char *)&rec, sizeof(rec),1,fp) = 1) {
/* */ if(/* */) {
fseek(fp, -(long)sizeof(rec), 1);
fwrite((char *)&rec, sizeof(rec), 1,fp); fseek(fp, 0l,1); } }
5.3 缓冲输出与内存分配
共分享92篇相关文档