看完《C陷阱与缺陷》,忍不住要从新翻一下,记录一下与本身的惯性思惟不符合的地方。记录的是知识的增量,是这几天的流量,而不是存量。
这本书是在ASCI C/C89订制以前写的,有些地方有疏漏。编程
第一章 词法陷阱
- 1.3 C语言中解析符号时使用贪心策略,如x+++++y将被解析为x++ ++ +y,并编译出错。
- 1.5 单引号引发的一个字符表明一个对应的整数,对于采用ASCII字符集的编译器而言,'a'与014一、97含义一致。
- 练习1.1 嵌套注释(如/*/**/*/)只在某些C编译器中容许,如gcc4.8.2编译时是不支持的。
第二章 语法陷阱
- 2.6 else始终与同一个括号内最近的未匹配的if结合
第三章 语义陷阱
- 3.1 int a[12][31]表示的是一个长度12的数组,每一个元素是一个长度31的数组。
- 3.1 在须要指针的地方若是使用数组名来替换,那么数组名就被视为其下标为0的元素的指针,p = &a的写法是非法的(gcc4.8.2只是警告)。
- 3.2 如何链接两个给出的字符串s、t?细节很重要,书中给出的答案以下:
char *r,*malloc()
//原文称不能直接声明一个s、t长度之和的数组,但c99能够声明变长数组,已经能够了
//记得要把长度加1
r = malloc(strlen(s) + strlen(t) +1);
//必须判断内存是否分配成功
if(!r){
complain();
exit(1);
}
strcpy(r,s);
strcat(r,t);
......
//完成以后必定要释放r
free(r);
第四章 链接
- 4.2 int a若出如今全部函数体以外,则完成了声明与定义(分配存储空间)。而extern int a;只是声明,说明a的存储空间是在其余地方分配的,不是定义;所以必须在别的某个地方定义,同一个或不一样的源文件都可。
- 4.3 static修饰符能够将一个函数或变量的做用域限制在一个源文件以内,不会与其余文件中的同名量发生冲突
- 4.5 声明与定义必须严格相同,而数组和指针是不一样的。
- 4.6 如何避免声明与定义不符?遵照“每一个外部对象只在一个地方声明”的规则便可。通常放在头文件中,全部用到此外部对象的源文件都要包括此头文件,定义此对象的文件也应该包括此头文件。
第五章 库函数
- 5.1 getchar()返回整数,不能把返回值赋值给char型变量再与EOF比较,由于EOF定义为-1,应该赋值给int型变量。
- 5.2 若是要对文件进行连续的read和write操做,则中间必须插入fseek函数调用。
- 5.3 setbuf(stdout, buf);能够强制将buf指向的char数组设为缓冲区,改变输出缓存大小。
- 5.3 书中使用缓冲区把stdin的内容复制到stdout的程序是错误的,由于缓冲区内容的写出直到缓冲区满或调用fflush才开始完成。能够把buf声明为静态的或者malloc在堆中,防止main函数结束后buf清空。
- 5..1 一个程序异常终止时,程序输出的最后一部分经常丢失,可使用setbuf指向一个空指针做为缓冲区
- 5..2 putchar/getchar在stdio.h中使用宏实现,若是没有包括stdio.h,很大可能仍能运行,可是使用相应的函数代替,速度下降。
第六章 预处理器
- 6 宏只是对文本处理,是一个表达式,不是函数或语句
- 6.1 宏定义最好把每一个参数和整个表达式使用括号括起来防止出错。
- 6.2 若是一个操做数在两个地方用到,将被求值两次。解决方案:操做数应该没有反作用;将宏实现为函数。
- 6.2 宏可能产生很是庞大的表达式。
- 6.3 宏的分号的使用很麻烦,assert的一种正确实现:#define assert(e) ((void)((e)||_assert_error(__FILE__,__LINE__)))
- 6.4 typedef struct foo FOOTYPE是类型定义语句,定义了一个新的类型。
第七章 可移植性缺陷
- 7.4 编译器实现可能将字符看成有符号或无符号的。char转换为int时结果未定义,可使用unsigned char避免。
- 7.4 将字符变量转换为无符号整数时应该使用(unsigned char)c而不是(unsigned)c,后者将c转换为int再转换为unsigned int。
- 7.5 除法运算速度大大慢于移位。
- 7.7 整数除法运算时,仅规定商 x 除数 + 余数 == 被除数,大多数实如今负数的除法时,只保证余数与被除数正负号相同,商与被除数的符号无关。应尽可能使n为无符号数。
- 7.9 toupper/tolower函数均采用int型参数,实现时要检查输入是否符合要求,采用置位实现很是快速。
- 7.11 要求一个按位输出long型数字。须要考虑:不能对-n求值,可能溢出(边界条件),应该把n转换为负的再处理;余数的符号未知,应作归一化处理。
- 7..2 atoi函数把字符串转换为long型整数,应该按照负数来处理以免溢出。