《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的配对。

posted @ 2023-02-05 02:27  尘埃之思  阅读(66)  评论(0)    收藏  举报