Mar 24

之前已经学习完第一章,现在开始学习第二章,《程序的灵魂--算法》。现在就从第二章的总论开始学习。以下是我的心得。

1、最让我惊讶的,是谭师傅居然把Niklaus Wirth的名写成了Nikiklaus。牵狗查了一下,有“Nikiklaus Wirth”字样的还不少,都是中文网站,有课件也有文章。不禁让我想起《蜘蛛侠》中的一句台词:“With great power, comes great responsibility”。谭师傅好歹也算是个名人,要注意一下影响。

2、不光是名字,谭师傅把那句名言也整反了。人家说的明明是“算法+数据结构=程序“,谭师傅一下就整成了”数据结构+算法=程序“。虽然说加法有交换律,不过呢,这可不是一个公式,而是一本书的名字。还是那句话,要注意一下影响。

3、谭师傅把数据结构比作食材,把算法比作烹饪的步骤,把算法提高到“灵魂”的高度,而认为“数据结构”只是“加工对象”。虽然没有明说,但给人的印象确实是“算法就是一切”,而数据结构则成了固定、死板、不需要太费心的东西。看到这里,我除了叹气以外也无话可说。算法与数据结构从来都是相辅相成,必需同时设计。一个好的数据结构能够极大的简化算法,并且让程序更容易读懂,更容易维护。这也正是为什么说“算法+数据结构=程序“的原因。这本来是任何一个合格的软件工程师都应该明白的东西。难怪网上有人劝谭师傅先自己试着做做软件开发再来写书。

4、本来算法和数据结构是独立于具体的编程语言、环境的(即同一个算法或数据结构可以用不同的语言实现)。也正是因为这样,算法、数据结构以至于算法复杂度等等概念才有研究的必要。在特殊情况下,某种语言甚至可以看成是专门为了某种算法和数据结构才被发明的。谭师傅这本书本来是讲C语言的,为什么不能专注于C语言呢?讲自己不擅长的东西也是对读者不负责。从整第二章来看,谭师傅眼中的“算法”,大概也就是先做A,再做B,如果C成立再回头做A之类的东西,还处于社会主义初级阶段。同学们可千万要记住了,“革命尚未成功,同志仍須努力“。

好了,概论就学习到这里。下次仔细分析谭师傅的算法

Mar 23

前面已经学习过1.3节,现在来学习1.4节,《运行C语言的步骤与方法》,也是第一章最后一节。以下是学习心得。

1、谭师傅说,“所谓程序,就是一组计算机能识别和执行的指令。每一条指令使计算机执行特定的操作。”,后面紧接着又说“计算机…不能识别和执行高级语言写的指令”。

心得:由第一句对程序的定义和后面紧接着的这句话,我恍然大悟:原来C语言写的那不叫程序啊,不对,这本书明明叫做《C程序设计》的,我晕了。

2、谭师傅教导我们说,要“上机运行”一个C语言程序,必须先“在纸上写好一个程序后“,再…

心得:天啊,这难道是学英语时单词写得不够多的报应?

3、谭师傅说,“目前使用的大多数C编译系统都是集成环境(IDE)的”。

心得:谭师傅这一句话漏了自己的底:对UNIX是七窍通了六窍。当然,后面还有其它的心得可以佐证。

4、谭师傅又教导我们说,“不应当只会使用一种编译系统,而对其他的一无所知。“

心得:结合上一条心得,我心里那个汗哪。

5、谭师傅用的文件名都是诸如c1.c、c2.c、f.exe等等。

心得:够简洁、够有力,够雷人。

6、谭师傅说,“Turbo C++…也能编译以.c为后缀的C源程序(按照Turbo C++的语法规定进行编译)”。

心得:莫非Borland公司自己创造了一套C语言语法?还是谭师傅在为 (a=3*5)=3*4 这样的“谭氏表达式”作伏笔?

7、谭师傅在第一章结束的题目中,要求学生“根据自己的认识,写出C语言的主要特点“。又问,“C语言的主要用途是什么?它和其它高级语言有什么异同?“

心得:我若是谭师傅的学生,一定会不知所措。还没学会呢,哪来的什么”认识“?如果原来没学过什么其它高级语言,又哪里来的什么异同?原来学C语言也是背书?

好了,第一章学习完毕,以后接看学。

Mar 20

前面已经学习过第1.2节。现在接着学习第1.3节,《简单的C语言程序介绍》。

这一节以三个简单的C程序为例,讲解了C语言的基本结构、语法,以及初步的函数的概念。看得出有刻意求新的地方,比如很有味道的“Hello World”就变成了枯燥无味的“This is a C program.”。

这一节的主要学习心得如下:

1、变量是在“声明”的时候就“定义”了,不管有没有同时给它赋值。如例1.2和1.3的注释部分,以及谭师傅在解释例1.2时对“int a,b,sum;”讲解说它“是声明部分,定义变量a和b,指定a和b为整型“。

2. 一行可以写好几个语句,只要写得下。

3、函数返回值的类型也可以叫做“函数的类型”。

4、一个函数所调用的函数是在本身函数体的声明部分声明的。

当然,以上心得都是作为反面案例来学习的。

好了,1.3节就学习到这里了。以后接着学习

注:原本有更多的心得,是针对第二版写的。现在发现第三版已经改了不少,所以就以第三版为准了。

Mar 19

之前已经学习过1.1节,现在再来学习1.2节,“C语言的特点”。

谭师傅说C语言“数据结构丰富,具有现代化语言的各种数据结构“。我看到这里就蒙了。C语言里只有数组还可算得上是个“数据结构”,丰富在哪里啊?再往下看,原来谭师傅说的是C的“数据类型”丰富,可以实现复杂的数据结构。这都哪跟哪啊?我是不是也可以说汇编语言的“数据结构丰富”,因为用汇编也可以实现各种复杂的数据结构?

谭师傅说C的“语法限制不太严格”。与C相对的,“一般的高级语言语法检查比较严,能检查出几乎所有的语法错误。而C语言…放宽了语法检查“。我就不懂了,语法检查不是编译器干的事么?如果一个编译器不能检查出所有的语法错误,那一定是假冒伪劣产品。写C语言程序还能不按它的语法规则写?我又一次看到了“谭氏编译器”的身影。

谭师傅还匠心独具地解释了一番“高级语言中的低级语言”和“中级语言”,并认为C语言一般被称为“高级语言”,原因是它必需“通过编译、连接才能得到 可执行的目标程序”。“目标程序”这个词不伦不类,暂且不提。难道谭师傅写的汇编程序(如果他写的话)是不需要经过编译和连接就可以得到可执行程序的?这样看来,不光有谭氏C编译器,还有谭氏assembler。

在第二版中,谭师傅还列出几种语言作为高级语言的例子,其中居然连一个functional language都没有。试想,如果BASIC和FORTRAN算是高级语言,那C++/Java/C#不就成了超高级语言,而Lisp、Prolog、ML就成了超超高级语言了(说起来怎么这么绕口:))。还好第三版里这些被去掉了。

谭师傅还提到“UNIX和C不可分”。话是没错,不过谭师傅为什么还在用TC?

直看到这一节结束,谭师傅对诸如Linux、Java、C#等等只字未提(像PHP之类就不强求了),只讲BASIC、PASCAL、FORTRAN、COBOL如何如何,让人不禁想起七、八十年代的美好时光。

谭师傅还认为,C++只是编写大型软件用的,没必要一开始就学,而且学了C再学C++就很容易,因为“面向对象的基础是面向过程”。真的是这样吗?C和C++各有所长,但绝不是什么大型还是小型的问题。OOP与Procedure Programming之间的关系也绝非谁是谁的基础这么简单。

好,1.2节学习完毕。下次接着学习

Mar 18

谭师傅的书流传之广,令人叹为观止。于是决定好好把谭师傅的书好好研读一下。能够完整下载的,只找到了一个扫描版的《C语言程序设计》第二版。Google Books倒是有第三版部分章节。以后若不加说明,都是指Google Books里能够看到的内容。

以下是我对第一章1.1节的读书心得。

心得1:谭师傅年份拎不清。例如:

1、B语言应该在1969年在PDP-7实现,1970年在PDP-11上实现,而不是谭师傅说的1970和1971年。
2、第一个ANSI C标准于1989才正式出版(即C89),而不是谭师傅所说的1983年(1983年刚刚成立X3J11委员会)。

心得2:谭师傅事实也拎不清。例如:

3、谭师傅说ISO接受“87 ANSI C”作为ISO C标准(即C90)。事实上,不存在什么“87 ANSI C”。C90和C89区别非常小。
4、Thompson从来没有在PDP-7上用B语言实现过Unix。事实上,PDP-7上B语言编译器不直接产生机器代码,而且Thompson也从来没有过这样的打算,因为PDP-7的硬件限制太多。

心得3:谭师傅喜欢想当然。例如:

5、谭师傅说B语言的B是取其前身BCPL的第一个字母,C语言的C是取其第二个字母。事实上这两种语言的命名历来都有两种说法,就连Dennis Ritchie都没有像谭师傅说得那样斩钉截铁。

心得4:谭师傅语言表达很成问题。例如:

6、谭师傅说C语言是一种“系统描述语言“。这玩艺儿到底是啥?
7、谭师傅说Brian Kernighan和Dennis Ritchie“合称K&R”。实际上他们合著的那本经典书才被称为K&R。

1.1节学习完毕,以后再接着读

Mar 13

昨天看了张云楼的《谭浩强大师的世界纪录》,也只是一笑了之。大陆的计算机教材,也就是那么回事。翻译的生硬、错误多,自己写的干巴巴、过时、错误多。就拿谭浩强的C语言教材来说,我只在近20年前读过,只记得味如嚼腊。现在唯一还有印象的,是谭师傅花了很大一段文字说明他为什么认为struct应该译作“结构体”,而不是“结构”。对中国人来说,想学好计算机,能阅读英文资料是一项必不可少的能力。

没想到今天还有一位“注意版本”同学不服气,一定要为谭师傅辩护,却不免底气不足。不过倒引起我的兴趣,把双方的文章又看了看,觉得有些问题不得不说。张指出了谭书三处问题(实际上是4个),总结如下:

1、谭书:TC中int 32767+1 = -32768,long 32767+1 = 32768。张质问:“敢问谭教授上机试过没有,我试过了,不行。”
2、谭书:变量可以作左值,…常变量不能作左值。张质问:“有常量、有变量,什么叫常变量。”
3、谭书:赋值表达式能够作为左值,例如(a=3*5)=4*3可得a为12。张质问:”真够经典的了,不知谭教授怎样创造出来的?“
4、谭书:ANSI 标准允许switch后面的“表达式”为任何类型。张质问:“不知谭教授真的看过ANSI标准?”

而“注意版本”同学则认为“张云楼老师说发现了大量低级错误,恰恰说明其见识太少”。并在扯了一阵什么project和makefile以显示其“见识”并不“太少”之后,作了如下回复(对于2没有回复):

1、“相信教材作者至少在某个版本上试验过,很可能后来版本更新了引起问题。”
3、“在有些版本的编译器确实是支持的。”
4、“除非你查遍所有版本都同样说法,才能指责谭浩强的教材。“

张云楼号称自己是“教了10几年的C语言“的“计算机教师“,暂且认为是中国计算机教师的一个样本吧。而见多识广的“注意版本”可算是(至少是曾经的)学生。一师一生,都是半吊子。不用说追英赶美了,和印度比比都觉得不好意思。对于张云楼提出的问题,我的看法如下。

1、谭书说明了是TC。我不知道张老师用什么“试过了”,遗憾的是,我刚刚试验的结果,TC2.01和TC++3.0结果都一样,就是谭师傅讲的是对的(这里要说明的是TC最高版本就是2.01,以后改为Borland C)。“注意版本”同学却连试一下都没有,就乱说什么“版本更新”的问题,估计是微软的东西用得太多了。

2、我来指导一下张老师。所谓“常变量”,就是constant variable,例如 “const int i = 20;”。这时 i 仍然是变量(variable),但其值不能被程序改变。这样的变量在第一次赋值后,就不能再作为左值出现。

3、不知道“注意版本”同学是在什么“版本”的编译器上试过?什么版本的C语言表态式可以作左值?不会是谭氏版吧?

4、我可以很明确地告诉不愿读书、不愿试验但见多识广的“注意版本”同学,不管你注意的是哪个版本的ANSI标准,switch都只能接受整数类型为参数。对于这一点,完全不需要看ANSI标准(很贵又很长),只需要看看C语言经典K&R(The C Programming Language)第二版就知道了。据我所知,这本书在国内已有不少影印本,网上也有的下载,查一查还是不难的。

没有想到的是,这么多年来,大陆的学生仍然用的是这种教材。以后有机会一定要把谭师傅的书好好研读一下。