C陷阱与缺陷笔记

时间:2022-12-28 11:13:13

第一章 词法陷阱

1.1 =不同于==

1.2 &与|不同于&&与||

1.3 词法分析中的”贪心法”

  • 编译器将程序分解成符号的方法是,从左到右一个一个字符读入,如该字符能组成一个符号,再读入下一个字符.判断两个字符组成的字符串是否可能是一个符号的组成部分.如能,继续读入下一个字符.重复上述判断.

1.4 整型变量

  • 注意进制 0开头:8进制

1.5 字符与字符串

  • 用单引号引起的一个字符实际上是代表一个整数! 整数值对英语该字符在编译器采用的字符集中的序列值.
  • 用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针.

第二章 语法陷阱

2.1 理解函数声明

2.2 运算符的优先级问题

  • 类型转换也是单目运算符
  • 条件运算符是三目运算符

2.3 注意作为语句结束标志的分号

2.4 switch语句

  • break

2.5 函数调用

  • 若f是一个函数
  • f(); // 调用函数语句
  • f; // 函数f的地址!

2.6 “悬挂”else引发的问题

  • 注意
    // 大括号写
    if(){
    //…
    }
    else{
    //…
    }

第三章 语义陷阱

3.1 指针与数组

  • C语言中只有一维数组,而且数组大小必须在编译阶段作为一个常数确定.
  • 任何指针都是指向某种类型的变量!
  • siseof(a) //a是一个数组,结果是整个数组a的大小,而非指向数组a的元素的指针的大小.

3.2 非数组的指针

  • 在C语言中,字符串常量代表了一块包括了字符串中所有字符已经I一个空字符’\0’的内存区域的地址.

3.3 作为参数的数组声明

  • 将数组作为函数参数毫无意义! C语言中会自动将作为参数的数组声明转换为相应的指针声明!

3.4 避免”举隅法”

  • synecdoche: 用宽泛的词语来代替相对较窄的词语..
  • 指针及地址啊!
    char *p,*q;
    p=”xyz”;
    //p的值是’x”y”z”\0’组成的数组的起始元素的指针

3.5 空指针并非空字符串

  • 编译器保证由 0 转换而来的指针不等于任何有效的指针.
    #define NULL 0

3.6 边界计算与不对称边界

  • 在C语言中,一个拥有n个元素的数组,它的元素下标从0到n-1

3.7 求值顺序

3.8 运算符&& || !

3.9 整数溢出

  • 无符号数,没有所谓的”溢出”一说?
  • 有符号数,”可能”发生”溢出”
  • INT_MAX

3.10 为函数main提供返回值

第四章 链接

4.1 什么是链接器

  • 分别编译: 编译器一般每次只处理一个文件..所以不能检出那些需要一次了解多个源程序文件才能察觉的错误..
  • 典型的链接器把由编译器or汇编器生成的若干个目标模块,整合成一个被称为载入模块or可执行文件的实体..
  • 链接器的一个重要工作就是处理命名冲突..
  • C语言实现中提供了 lint 程序

4.2 声明与定义

4.3 命名冲突与static修饰符

  • static修饰符是一个能够减少命名冲突的有用工具..
    static int a;
    // 其含义与下面的语句相同
    int a;
    // 只不过a的作用域限制在一个源文件中,对于其他源文件,a是不可见的.
    // static不仅适用于变量,也适用于函数

4.4 形参 实参与返回值

4.5 检查外部变量

4.6 头文件

库文件

5.1 返回整型的getchar函数

  • 有关库文件的使用,最好的建议:尽量使用系统头文件.

5.2 更新顺序文件

5.3 缓冲输出与内存分配

  • 当一个程序生成输出时,是否有必要将输出立即展示给用户? 程序输出有两种方式.一种是即时处理方式.另一种是先暂存起来..然后大写写入的方式..

5.4 使用error检测错误

5.5 库函数signal

第六章 预处理器

  1. 需要将某个特定数量 在程序中同一修改
  2. 大多数C语言实现在函数调用时,会带来大量系统开销.

6.1 不能忽视宏定义的空格

6.2 宏并不是函数

  • 最好在宏定义中把每个参数都用括号括起来,同样,整个结果表达式也应该括起来.以防止宏用于一个更大一些的表达式中出现问题.

6.3 宏并不是语句

6.4 宏并不是类型定义

第七章 可移植性缺陷

7.1 应对C语言标准变更

7.2 标识符名称的限制

7.3 整数的大小

  • C语言中提供了3中不同长度的整数: shrot int long
    • 三种类型的整数其长度非递减.
    • 一个普通(int类型)整数足够容纳任何数组的下标
    • 字符长度由硬件特性决定!!!
  • typedef关键字

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

7.5 移位运算符

7.6 内存位置0

  • null指针并指向任何对象
  • 在所有C程序中,误用null指针的效果都是未定义的.

7.7 出发运算发生的截断

7.8 随机数的大小

7.9 大小写转换

  • 库函数 toupper 和 tolower

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

  • C语言提供了3个内存分配函数: malloc realloc free

第八章 建议

最重要的技巧是 知道自己在做什么!!!

对程序的组合方式的理解非常重要!!!

8.1 建议

  • 不要说服自己相信”皇帝的新衣”
  • 直接了当地表明意图
  • 考察最简单的特列
  • 使用不对称边界
  • 注意潜伏在暗处的bug
    坚持只使用C语言众所周知的部分..避免使用生僻语言特性
  • 防御性编程