读书笔记--C陷阱与缺陷

  要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便)。

 看到大家都推荐看看  C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅。

决定将书中重要的知识点和易错点记录下来方便自己复习和他人学习~~不多说了,下面开始。

第一章:词法陷阱

  1. 在C语言中,符号(程序文字)之间的空白(包括空格符、制表符、换行符)将被忽略。书中举了一例:
 1 if (x > big) big = x;
 2 可以写成:
 3 if
 4 (
 5 x
 6 >
 7 big
 8 )
 9 big
10 =
11 x
12 ;

其实我们编码的时候已经涉及到了,比如C标准规范就要求多用空格符来对齐;过长的判断式也会分为两行书写等。

这些所谓的空白当然是被忽略了,不然编译器没法理解程序意图了。。。

  2. 在词法分析中,作者指出:如果/是为判断下一个符号而读入的第一个字符,而/之后紧挨*,那么无视上下文,这两个字符都被当做一个符号/*,表示一段注释的开始。

由此可能会出现以下问题:

    y = x/*p;

  语句想用x除以p说指向的值,结果赋给y。但是/*被解释为注释,于是语句直接将x赋给y。

其实这样写(*p)就可以很好避免。y = x/(*p);

  这种错误是有可能出现的,好在现在的IDE注释都会变色,应该容易察觉。

  3. 字符和字符串:

  学C语言都知道单引号表示字符,双引号表示字符串。

  其实单引号引起的单字符实际上代表一个整数,该整数值对应于该字符在编译器采用的字符集的序列值。

一般采用ASCII字符集,即’a’与97(十进制)含义严格一致。

  而双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组被双引号之间的字符串+一个额外的二进制值为0的字符’\0’(C中常用来表示结束)初始化。

    书中举例:

1 printf(“hello world\n ”);
2 与
3 char hello[] = { ‘h’, ’e’, ‘l’, ‘l’, ‘o’, ‘ ’, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘\n’, 0 };
4 printf(hello);    是等效的

上面代码跑了下确实是对的,但其实将hello[]写成如下形式更有可读性。

  char hello[] = {‘h’, ’e’, ‘l’, ‘l’, ‘o’, ‘ ’, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘\n’, ‘\0‘};

  

  4. 书中还提到整型数(16/32位)的存储空间可容纳多个字符(8位),那么有的编译器允许一个字符串常量中包括

多个字符。如‘yes‘代替“yes”。

  按照单字符的整数本质,作者做了个实验:

1     int t1=‘a‘;
2     printf("%d\n", t1);
3     int t11=‘aa‘;
4     printf("%d\n", t11);

输出结果:

  97就是‘a‘的asc码值好理解,但是‘aa‘的值24929可能就是和编译器与存储方式有关系,作者暂时也没懂,有大神可以评论讲解下~~

  第一章也就这些注意点了,期待第二章!

时间: 2024-10-20 11:11:21

读书笔记--C陷阱与缺陷的相关文章

读书笔记--C陷阱与缺陷(七)

第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一种判断编译器如何处理内存0的代码: 1 #include <stdio.h> 2 int main() 3 { 4 5 char *p; 6 p=NULL; 7 printf("location 0 contains: %d\n", *p); 8 9 return 0; 10

读书笔记--C陷阱与缺陷(四)

第四章 1. 连接器 C语言的一个重要思想就是分别编译:若干个源程序可在不同的时候单独进行编译,恰当的时候整合到一起. 连接器一般与C编译器分离,其输入是一组目标模块(编译后的模块)和库文件,输出是一个载入模块(执行文件). 2. 命名冲突与static修饰符 static修饰符可有效减少命名冲突! 如: static int a; 与 int a; 声明含义相同,但是前者限制a的作用域在一个源文件(.c)内,其他源文件是不可见的.但后者都是可见的会产生命名冲突. 如果若干个函数需要共享一组外部

读书笔记--C陷阱与缺陷(二)

第二章 1. 理解函数声明 书中分析了复杂的类型声明方式,也说明了使用typedef声明会更好理解,推荐大家使用typedef进行函数声明. 书中类型分析一层一层挖掘,让读者可以理解多层嵌套的类型含义,有时间的读者可以去看看,笔者不再重复. 既然书中推荐使用typedef进行函数声明,我们就来研究下typedef: typedef主要用于定义一种类型/结构体的别名. 从字面上看和C的宏定义 #define 挺像的,但是define只是简单的参数替换,如果不注意括号很容易产生预期之外的错误. 在指

读书笔记--C陷阱与缺陷(六)

第六章 1.预处理器:预处理器先对代码进行必要的转换处理,简化编程者的工作. 它的重要原因有以下两点: a. 假如要将程序中出现的所有实例都加以修改,但希望只改动程序一处数值,重新编译实现. 预处理器可以做到这点,通过将这个数值设为显式常量. b. C语言函数调用花销大,希望有一个程序块看上去像函数确没有函数调用的开销. 2.宏定义的空格不能忽视 宏定义只是简单的文本替换,记住这个本质可以避免很多错误. 如: #define f  (x)  ((x)-1) 上式意思是: f(x)代表((x)-1

《C陷阱与缺陷》读书笔记

<C陷阱与缺陷>读书笔记 1.编译器中的词法分析器负责将程序分解为一个个符号.C语言中,符号之间的空白 (包括Space ,Tab , Enter) 都将被忽略,但一个符号的中间不能有空白,否则可能被解释成为另一个或几个符号. 2.编译器将程序分解成符号的方法是从左到右逐个字符读入,如果该字符可能会组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分:如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已经不再可能组成一个有意义的

C陷阱与缺陷 读书笔记

C陷阱与缺陷 1.  typedef用法: ①    定义一种类型别名,而不是简单的宏替换: char *pa,pb;(注意:pb并没有定义为指针,虽然你可能想这么定义它) typedef char* PCHAR PCHAR pa, pb; ②   用在旧的C代码中,帮助struct.以前的代码中,声明struct新对象时,必须带上struct,即形式为:struc结构名对象名,如: struct tagPOINT1 { Int x; Int y; }; struct tagPOINT1 p1;

C陷阱与缺陷 —— 读书笔记-1、词法“陷阱”

<C陷阱与缺陷>是由Andrew Koenig所著,高巍译.Andrew Koenig是AT&T大规模程序研发部(前贝尔实验室)成员,不仅有着多年的C++开发,研究和教学经验,而且还亲身参与了C++的演化和变革,对C++的变化和发展起到重要的影响. 第一章    词法陷阱 编译器中负责将程序分解为一个一个符号的部分,一般称为"语法分析器". 1.1    = 不同于 == while (c='' || c==' ' || c==' ') c=getc(f); 这个循

&lt;读书笔记&gt;软件调试之道 :问题的核心-如何修复缺陷

声明:本文档的内容主要来源于书籍<软件调试修炼之道>作者Paul Butcher,属于读书笔记.欢迎转载! 修复缺陷 对于一个好的修复来说,不仅仅是让软件运行正确,还需要为将来奠定基础.一些列零散的未经仔细考虑的修改,都将是原本的简洁设计逐步消失. 好的修复必须同时实现以下目标: 修复问题 避免引入回归 维持或者提高代码的整体质量 -----------需要参考的规则如下---------- 1.清除障碍 确保一切从头开始,当你不舍得抛弃诊断阶段所做的修改时,利用源码控制系统. 需要对所做的修

《C陷阱与缺陷》学习笔记(一)

前言和导读 "得心应手的工具在初学时的困难程度往往超过那些容易上手的工具."比较认同这句话.我至今觉得自己其实还是个刚入了门的初学者. 第一章 "词法"陷阱 由于之前学过编译原理,对编译器词法分析(主要是符号识别过程)比较了解,理解起来不困难. 在讲到"="和"=="."|"和"||"."&"和"&&"时,联想起以前见过一些