引言
二十几年的经典之作,读完确实有所收获。读完这本书,感觉作者主要是想通过介绍一些C编程的缺陷,让读者以后能在编程时保持谨慎,多思考,不要想当然!
以下为个人笔记,以供日后查阅。
第一章
本章主要讲述的是一些词法“陷阱”。C语言通过单个或多个字符组合构成符号(token),符号是程序的基本组成单元,编译器通过词法分析器,将程序分解成一个个符号。
1=不同于==
在C中混淆使用的情况,多见于使用过其他语言(如Pascal和Ada)的编程者,因为在有的语言中,“=”即比较运算符。
另一种错误使用情况,就是粗心漏写了。
2词法分析中的贪心法
从左到右尽可能多的读入字符。
例1:a---b。
上述例子,采用贪心法进行词法分析的编译器会理解为 (a--)- (b)。不能理所当然认为会产生(a)- (--b)的效果。
例1_改:a- --b或是a-(--b)。
为了达到预期效果,可以用空格来隔断,或是使用()。
例2:y=x/*p /*p指向除数*/
实际解读则为:y=x /*p /*p指向除数*/ 红色字体为注释
3整数对齐
struct {
int part_number;
char *description;
}parttab[ ] = {
046, "left" ,
047, "right",
125, "middle"
}
为了格式对其,十进制数写成了八进制。
4单引号与双引号
单引号括起一个字符(‘a’)代表整数,双引号括起的一个字符(“a”)代表一个指针。
char *slash = '/';
printf('\n');
上述两条语句均是错误。
第二章
1函数指针
变量fp是函数指针,调用该函数方法为:(*fp)()。ANSI C标准允许简写fp()。
注意区分*fp()和(*fp)()。*fp()等价于*(fp()),因为()优先级高于*。
2运算符优先级
3注意swith语句中case后的break。有时候是故意省去。
case SUBTRACT:
opnd2 = - opnd2;
/*此处没有break*/
case ADD:
. . .
省去break的用法,适用于对某一情况进行特别处理,而其他步骤又与其它情况的处理相同的操作。
第三章
1指针与数组
1.1 C中只有一维数组,数组元素为任何类型,可以是一个数组,所以可以“仿真”多维数组。
1.2 对于数组,我们只能做两件事:确定数组大小;获得指向该数组下标为0的元素的指针。对数组的其他操作,乍看上去是以数组下标进行运算,实际是通过指针进行的。
2分配空间
使用malloc()函数的时候,注意检查其返回值,即是否成功分配内存。
strlen()未计算结束标志空字符‘\0’.
3数组声明
只有在作为函数参数时,数组名会立刻被转换成指向第一个元素的指针。所以,数组作为函数参数时,声明可以是指针或数组。
其他情况,如变量声明,则不可。
4字符串常量
不要试图修改符串常量的内容,如下例所示:
char *p;
p = "xyz";
p[1]='Y';
即使有编译器允许,也不提倡。
5空指针
整数转换为指针,所取得结果取决于编译器。
特例:0。 0转换而来的指针不等于任何有效指针。处于代码文档化考虑,常用一个符号代替:#define NULL 0
6溢界元素
超出数组范围的下一个元素地址是存在的。改地址可以进行复赋值和比较,但不能引用。
7求值顺序
C语言中,规定求值顺序的运算符:&&、||、,、?:。
&&和||是先左后右,若左侧值即可确定结果,不对右侧求值。
<