《C陷阱与缺陷》读书笔记
第一章 词法“陷阱”
1.1 =和==不一样
1.2 &和|是按位与和按位或,&&和||是逻辑运算符
1.3 词法分析中的“贪心法”
C语言的规则是:每个符号应该包括尽可能多的字符。
例如:y = x/*p /* x除以p指向的值*/ 实际结果是x的值被赋给y,后面的全是注释
y = x / *p /* x除以p指向的值*/ 这样是对的
所以要注意二义性的问题。
1.4 整型常量
0开头的整型常量会被当成8进制数,要注意。
1.5 字符和字符串
C语言的单引号和双引号含义不同。
单引号引起的字符实际上代表一个整数,比如‘a'根据ASCII码就是97;双引号引起的是字符串,代表的是一个指向无名数组的起始字符的指针。
第二章 “语法陷阱”
2.1 理解函数声明
float *h(int a);//h是一个函数,返回值是一个指向float的指针 float (*h)(int a);//h是一个函数指针,指向返回值是float的函数 (float (*)())是一个类型转换符,表示“指向返回值为float的函数的指针”
如何调用首地址为0的函数:答案是( *(void(*)()) 0 ) ()
分析这个表达式怎么得来的:
第一步,假定fp是一个函数指针,(*fp)()是调用fp指向的函数,可以简写成fp(),但是要注意这仅仅是简写。(*0)()就是我们想要的调用地址0指向的函数,但是编译器并不能理解,所以要把0用一个东西代替。
第二步,找到一个表达式代替0,用( void(*)() )0来代替,把常数0类型转换为“指向返回值为void的函数的指针”类型
2.2 运算符的优先级问题
要注意运算符的优先级
2.3 注意作为语句结束标志的分号
一般来说,在C或者C++程序中多写了一个分号不会有什么后果,它只会被视为一个空语句。例如下面这个定义语句,不会有什么后果。
int a = 1;;
要注意一些情况,下面这种情况,在if条件语句的表达式后多了一个分号是错误的。
if(); a=1;
在比如下面这种情况,return后面少了一个分号,就会变成return a=1;这样也是错误。
if() return a=1; b=1;
在比如下面这种情况,由于struct的定义末尾少了分号,会导致其变为main函数的返回值类型,也是一种错误。
struct { int a; int n; } main(){}
2.4 switch语句
switch(color){ case 1:printf("red"); break; case 2:printf("black"); break; case 3:printf("blue"); break; }
C语言把case标号当做真正意义上的标号,因此程序的控制流程会劲直通过case标号而不会受到任何影响。如果没有break语句,就会一直往下走。比如color=2,就会打印redblack。C语言的这种特性及时优势也是劣势,优势在于可以刻意的省去一些break达到特定的目的,劣势在于容易遗忘break导致错误。
2.5 函数调用
C语言要求:在函数调用的时候,即使函数不带参数,也应该包括参数列表。f是一个函数,调用它应该使用f()。
2.6 “悬挂”else引发的问题
else始终与同一对括号内最近的未匹配的if结合。所以要注意if和else的配对。

浙公网安备 33010602011771号