第1章 词法陷阱

严格规范词法书写,单引号与双引号不要混用。

第2章 语法陷阱

  • 理解函数声明

    1
    2
    //程序跳转到地址0处执行
    (*(void(*)())0)();
    1
    2
    3
    4
    void (*signal(int, void(*)(int)))(int);
    //typedef简化
    typedef void (*HANDLER)(int);
    HANDLER signal(int, HANDLER);
  • 运算符优先级

  • 语句结束标志的分号

  • switch

  • 函数调用

  • 悬挂 else 引发的问题

第3章 语义陷阱

  • 指针与数组

    1
    2
    3
    4
    5
    6
    7
    8
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
    //以下语句都是合法的
    printf("%d\n", *(a+5));
    printf("%d\n", *(5+a));
    //*(a+i)即数组 a 中下标为 i 的元素的引用,简记为 a[i]
    //由于 a+i 与 i+a 的含义一样,因此 a[i] 与 i[a] 也具有同样的含义
    printf("%d\n", a[5]);
    printf("%d\n", 5[a]); //5[a] 与 a[5]是一样的,但不推荐这样的写法
  • 非数组的指针

    • 字符串,注意字符串以 ‘\0’ 结尾,而 strlen() 计算长度并不将其计算在内。
  • 作为参数的数组声明

  • 避免举隅法

    1
    2
    3
    4
    char *p, *q;
    p = "xyz";
    //要记住 p 的值并不是字符串 "xyz",
    //p 的值是一个指向由 'x','y','z'和'\0'4个字符组成的数组的起始元素的指针
  • 空指针并非空字符串

    • 空指针不能使用该指针所指向内存中存储的内容,也不能解引用
  • 边界计算与不对称边界

  • 求值顺序

  • 运算符&&、||和 !

  • 整数溢出

    1
    if(a > INT_MAX - b) printf("溢出\n");
  • 为函数 main 提供返回值

第4章 连接

  • 什么是连接器
  • 声明与定义
    • extern 声明了一个对外部变量的引用,可以出现在函数内部。
  • 命名冲突与 static 修饰符
  • 形参、实参与返回值
  • 检查外部类型
  • 头文件

第5章 库函数

  • 返回整数的 getchar 函数
  • 更新顺序文件
  • 缓冲输出与内存分配
  • 使用 errno 检测错误
    • 在库函数没有调用失败的情况下,并没有强制要求库函数一定要设置 errno 为0,因此 errno 的值就可能是前一个执行失败的库函数设置的值
    • 库函数调用成功,仍旧可能设置 errno 的值(fopen 例子)
  • 库函数 signal

第6章 预处理器

  • 不能忽视宏定义中的空格
  • 宏并不是函数
    • 将宏定义中出现的参数用括号括起来
    • 将整个结果表达式也用括号括起来
  • 宏并不是语句
  • 宏并不是类型定义

第7章 可移植缺陷

  • 应对 C 语言标准变更

  • 标识符名称的限制

  • 整数的大小

  • 字符是有符号整数还是无符号整数

  • 移位运算符

  • 内存位置0

  • 除法运算时发生的截断

    • 不保证改变被除数的正负号,商的符号也会改变并且商的绝对值不变
    • 不保证当除数大于0时余数大于等于0且余数小于除数
  • 随机数的大小

  • 大小写转换

  • 首先释放,然后重新分配

  • 可移植性问题的一个例子

    1
    2
    3
    4
    //合法的写法
    for(int i = 0; i < 10; ++i){
    printf("%c\n", "0123456789"[i]);
    }

第8章 建议与答案

事前周密思考

对程序组合方式的理解尤为重要

在调试程序很长时间之后,疲惫不堪的程序员开始漫无目的地瞎碰,这里试一下,那里改一点,如果凑巧程序似乎可以运行了,便万事大吉。

  • 建议
    • 不要说服自己相信“皇帝的新装”
    • 直截了当地表明意图
    • 考察最简单的特例
    • 使用不对称边界
    • 注意潜伏在暗处的 Bug
    • 防御性编程
  • 答案
    • 指针不能相加但可以相减,结果是一个整数