《狂人C》读評(一) 理解程序设计篇

来源:互联网 发布:达芬奇软件官网 编辑:程序博客网 时间:2024/04/26 00:22

KBTiller兄在书籍扉页写指正,不敢指正,共同讨论。其实第一篇在年前已看完,由于过节心态浮躁一直没能总结记录。仔细想想自己真是拖拉的要命,再不写点东西对不起KBTiller兄的热情心意。本文大部分内容属于跟作者观点不一致的描述,我不是初学者,所以与其是读书笔记,不如说挑刺,尽管这样,书中还是有不少让我受益良多的地方。为了整理方便,主体内容分四个不同的部分,有的问题分界比较模糊,主观因素比重很大。至于为什么会这么长,那是因为我吹毛求疵了 :)。

一、精彩绝伦:我认为的很出彩的地方

1、最精彩的地方就是作者对细节对技术本质的探索,这点让我肃然起敬,这才是一个工程师应该具备的最高的品质。
2、P22 这个NEO画的真神了(KBTiller兄你想累死初学者么 ^^)。
3、P27 正文第3段第1行 “从这两条规则中发现在代码中只能写成正的十进制整数常数”,以前一直没有发现这点,读到这里真是如醍醐灌顶!P39的练习也是这个道理。
4、强调数据类型为基本是本书在技术上最特色的闪光点,数据类型的确是C语言的复杂所在,也是最难正确理解和使用地方,在我读的任何一本C语言书籍中还没有能系统的提及此,作者几乎对每个类型都做了深入分析,赞!
5、P71-P73 专门讲解了优先级结合性和运算次序的关系,这也是C语言中非常让人迷惑的地方,很多学了三五年的熟手还经常会犯错误,归根结底就是当初基础没打好,这里非常专业的分析了它们之间的关系,帮助初学者避免很多问题,这是很多C语言书籍尤其是国内教科书最欠缺的地方。
6、把=读成赋值,这个主意的确非常棒。
7、P111利用判断三角形种类这个问题来锻炼读者的逻辑判断能力是非常恰到好处的。初学者对代码的理解和控制不够熟练,往往会出现逻辑混乱的状况,这时候正需要加强练习。
8、P142用了小4页来讲解++ -- 运算符,帮”教授“和”专家“们的学生排除遗毒,作者大人辛苦了!


二、知识错误:知识点出错或者遗漏的地方

1、P7正文第4段第1行 “1987年87 ANSI C公布”,根据我在维基百科和C参考手册上的资料得知,ANSI C委员会是在1982年筹建,1983年正式成立的,而在1989年推出了ANSI C标准,俗称C89,这里是应该是错误了。
2、P13正文第8段第8行 “其中的字符都原样输出,除非出现“/”引导的字符序列或“%”引导的字符序列” 除了/和%引导的字符序列外,??引导的三字符序列也会被转换,尽管这个家伙几乎被遗忘了。
3、P13代码第3块第一行 “/" 、/n 、/a 、/b 、/t 、// 、/" 、/'”,这里怎么多了一个/",而且少了/v /f /r /? ,这属于字符转义符,还有别的转义符,描述不够精确。P49也有这个问题。
4、P14脚注1 “目前好像还没有实现可以使用汉字的C语言编译器” P16脚注1也是。VS2008中文版支持中文字符作为标识符,当时发现了这个的缘故是自己define出来一套汉编。看到这个,再版书籍的时候会不会考虑使用VC++ Express作为首选IDE呢,呵呵。
5、P24正文第4段第2行 “称呼这种编号的专业术语有很多种,有的叫ASCII码,有的叫内码,有的叫Unicode编码” ASCII码和Unicode编码都是内码的一种(如果英文也有内码这种说法的话),在这里把他们并列起来描述不适合,应该把内码删掉,换成其他的,如GBK/GB2312。
6、P48正文第4段第3行 “所以 signed是可以省写的这一说法,如果不说是错误的,那么至少是不严谨的。” 其实就是错误的,不能省略,在函数的声明和定义中如果一个使用 signed char 一个使用 char ,gcc下会编译出错,这点在CU论坛上也讨论过了,不多做解释,详细见链接:http://bbs.chinaunix.net/thread-1834841-2-11.html 从17楼开始,中有素质低下者请自动无视。
7、P82正文第10段第1行 “在{}之内,C99以前的规定是先把对编译器的事儿说完,再说让CPU做的事。也就是说要先写声明,再写语句”。C89也没有这个规矩阿,大概是K&R的C才会有这个要求(K&R要不要求我还真不清楚,但TurboC会要求)。

三、表述不当:在书中出现的位置不对或者容易引发歧义或者笔误疏漏的地方

1、P3正文第2段第1行 “通常我们所看到的计算机,一般都会有键盘、鼠标、显示器、机箱等几个部分”。这里讲机箱并不太合适,毕竟机箱只是一个空壳子,里面的内容才是最重要的,所以把“机箱”改成“主机”更适合。
2、P6正文第21段第1行 “汇编语言用助记符(add ,move)”,前面给出的例子是用的mov,但这里写出来是move,还是统一更好。
3、P7正文第4段第2行 “这个标准在1990年被国际标准化组织(International Standards Organization,ISO)”,ISO的英文标准名字是International Organization for Standardization 虽然看起来很古怪(貌似缩写成IOS更合适 --!)而且在后面P47也是用的International Organization for Standardization,所以这里要统一下。
4、P9正文第3段第1行 “由于使用了一段事先写好的程序段(这是编译器提供的)”。在这里说的是printf库函数,库函数不是编译器的一部分,但初学者又不知道啥叫函数库,所以建议改成“这是随编译器一起提供的”。
5、P16正文第8段第3行 “如表1-1所示,是C99新增的关键字。” 但是表1-1给出的是C99全部关键字,只有被加了标注的才是新增关键字,而且语法也有点问题。所以这里个人建议更改为“表1-1是C99全部的关键字。”
6、P20练习2.6 “使用printf()函数应在代码开头的位置通过编译是编译器处理命令对函数的名称做相应的说明“。 “编译是”应该是笔误。
7、P25正文第3段第2行 “在123后面写;是因为123无法被单独写在代码中。” 这句话理解起来不太得劲,建议改成“无法单独作为一句代码”更好。
8、P32正文第2段第1行 “内存(Memery Unit)这个词,本来就是记忆器件的意思。” Memery Unit最好翻译成内存单元,毕竟后面跟了个Unit。
9、P36正文15段第1行 “求一个负数的补码,还可以用2^机器数的总位数 减去这个数直接得到。” 减负等于加正,所以应该是“加上这个数直接得到”。
10、P49代码第5块 “/八进制数 /x十六进制数” ,C语言对转义字符的长度还是有要求的,八进制不能超过3个,十六进制不超过2个,这应该在后面写上。
11、P60正文第6段第2行 “然而12/10用%2d输出的是1,也就是说不会输出1前面的0,如果希望输出为02,则在%与2d之间应再在写个0——%02d” ,这里应该是要输出01,笔误写成02了。
12、P65习题12.“输入一身份证号码,输出这个人的生日。” 之前没有讲任何输入函数,所以这道题不适合在这里出现。
13、P67正文第3段 运算符介绍,有后缀运算符,但是没有说前缀运算符。
14、P69正文第3段第1句,“在这个表达式中,赋值号右面的表达式中的...” 前面一直把=称为赋值运算符,在这里忽然冒出个赋值号,不和谐阿。
15、P73脚注2 “利用续行的标志,从某种意义上说,单调也可以割裂”,“单词”笔误成“单调”,这里瞬间联想到严谨而又慈祥的高数老师。
16、P75正文11段第3行 “不要对cast运算有更多想入非非的非分之想”, 非分之想已经有想入非非的意思,再加上这个就显得太啰嗦,可以把想入非非去掉。
17、P84代码使用了scanf语句,这是本书第一次提到这个语句,但是没有任何讲解,建议解释下scanf的基本用法,简单的可以说下代码中出现的用法。
18、P128图4-6”程序开发过程示意图“ 这个图除了注释用的椭圆外看起来跟程序流程图差不多,有个结束框,但是开始框在哪里呢?为了确保完整性和一致性建议把开始框加上。
19、P131正文第7段第1行 “如果表达式的值不为0,执行语句,然后转至(0)再次求表达式的值” 上面没有(0)这一项,笔误了,应该是(1)。P138也有此错误,浮想联翩。
20、P136正文第3段第3行 “测试结果表明,输入0整数时,程序的运行是有问题的。” 这里少了一个字,应该是“输入0个整数“。
21、P137代码第2块第1行 ”while (printf("....")) /“ 这句代码后面有一个”/“ ,但是这里不用这个转义符代码也不会出错,显得多余了,/一般都是用到宏上。
22、P146正文第5段第3行 “画虎不成反成犬”,无论从用词还是用google得到的结果来看都是“画虎不成反类犬”更适合 ^^
23、P149代码第14,15行 见上面第21点。
24、P150正文第4段第2行 “此外for语句()内的表达式2部分也写的更简洁了。” 这里不只写的简洁,而且减少了判断次数,增加了运行效率,这点我认为也可以提一下。
25、P158正文10段第1行 ”序点之前要求计算机执行的运算及副效应在序点处必须完成“ 听起来怪怪的,这样如何:”计算机执行的运算及副效应在序点前必须完成“。

四、观点差异:不算错误,但是主观差异较大的地方

1、P9 脚注3 “使用IDE需要冒着被指责为菜鸟的风险,有些高手更喜欢表明自己不使用IDE而使用一些更为原始的开发环境。但总的来说,使用IDE开发软件更为方便。” 这句话我是赞同的,对于初学者来说IDE可以隐藏很多繁琐的细节,但有些细节对以后的发展会很重要,例如编译和链接。只有使用了命令行才会真正了解编译参数和链接过程,这是绝大部分C语言入门书籍没有教导,甚至没有提及的(大概跟平台差异性太大有关)。但是我觉得还是有必要在适当的时候提出一下(例如后面讲标准库的时候,或者把编译和链接作为高级课题专门开一章),不然初学者就根本忘记了有这么回事。
2、P32正文13段第1行 “变量是一段连续的、被命名了的、用于存放数据的、且可以求得其位置的、具有类型含义的存储空间” 这里有个比较特殊的变量是register变量,register变量是不能取地址的,因为它可能存在寄存器而非内存中。知道它存在寄存器(但不知道哪个编号的寄存器)算不算知道了位置了呢?这就是个见仁见智的问题。
3、从P71至P84,中间讲述了运算符优先级、结合性、类型转换、语句的各种概念这种纯理论的要点,个人觉得这些知识点太密集了,而且中间实际例题(完整代码的例题)也很少,这样给初学者压力很大,建议还是中间插入写例题缓和下进度,或者把知识点分散到别的章节。
4、P96正文第4/5段第1句 “由于3的确小于4,所以3<4的运算结果为1” “由于4<3这个关系并不成立,所以4<3的运算得到的值为0” 这里是第一次接触到关系运算,读者之前并没有任何关系运算的概念和知识,也不知有任何因果关系,所以这里的“由于...所以...”这种用词不当,用叙述式的语气更符合,但如果说是作者教导的推理也可以过得去。
5、P97 4.22 P139 5.22 标题都是 ”例题“ 这似乎不太正规,尤其是会出现在目录中的这种大标题,建议加上个限定语。
6、P110 P111代码块 “if (pfh_d==1)” "if (pfh_d==true)" 这是讲解_Bool类型用法的时候给的例子。但我们把一个量当作布尔类型的时候往往不会使用判等运算符,因为变量本真就有真假的含义,而不用绕一步判断是否和真相等。所以一般都这样写,更简洁更容易理解 "if (pfh_d)"。
7、P118 “大师如是说goto” 这里有点过于仓促了,我起码会在两个地方用到goto 1、不同地方产生不同的返回值,但为了确保代码结构清晰或者返回前有统一的事情要做,只用一个return返回。 2、循环/switch嵌套直接跳出。关于这点在CU上也讨论过了,不再多说。

原创粉丝点击