收藏 分享(赏)

the c programming language读书笔记.doc

上传人:kpmy5893 文档编号:7252015 上传时间:2019-05-10 格式:DOC 页数:15 大小:58KB
下载 相关 举报
the c programming language读书笔记.doc_第1页
第1页 / 共15页
the c programming language读书笔记.doc_第2页
第2页 / 共15页
the c programming language读书笔记.doc_第3页
第3页 / 共15页
the c programming language读书笔记.doc_第4页
第4页 / 共15页
the c programming language读书笔记.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

1、the c programming language 读书笔记更新时间:2011-08-21 14:01:08 来源 : 工业 360核心提示:the c programming language 读书笔记写在前面的话 作为计算机专业的学生来说,学习编程是一件不可避免的事情,然而,想成为真正的程序员(相信这是我们共同的理想),光凭我们在课堂里学到的那些东西是远远不够的,我们必须读大量的书,写大量的代码,经历一个艰难而快乐的过程之后,才能真正走入这个领域。因此利用好这个漫长的暑假,对于一个想学好编程的人来说是很有意义的。 为什么要学习 c 语言? 对于初学者来说,往往第一个要学的就是 c 语言。

2、为什么要学习 c 语言?对于今天这个惟利是图的世界来说,恐怕初学者第一要问的就是这个问题,他们中的很多人都会说在拥有c+,java,c这些高级语言的今天,c 能做什么呢?在网络中,得到的回答往往是:“c无所不能“,然后是一些语重心长的说教,呵呵,对于一个对编程知道不多的人来说这样的回答没有任何意义,因此我对这样的问题的回答是:那些高级语言的出现并不能结束 c 长达三十余年的长盛不衰,c 语言没有被任何一种语言所代替。相反,有些和 c 同时代的那些东西,恐怕今天的人连名字都忘了。在这个世界的每个角落都有无数的编程爱好者和从业人士对 c 有着无与伦比的狂热。这是事实,这是真理,它证明了一切。至于这

3、个原因何在?c 魅力到底在那呢?呵呵,这正是我们要在学习中必须弄明白的事情之一。现在就请你记住这个问题。 选择什么书? 选好了学习对象,那么最关键的无疑是选择一本好书,毫无疑问没有人能比 K/声明 int a;/定义字符数组和字符串 有人认为这两个是同一概念,是这样吗?不,完全不是,前者为容器(数据结构),后者为数据。这样说也许太理论化,好,我们来改写下那个 hello world#include “stdio.h“ #include “stdlib.h“ int main() printf( “post.contenthello world “ ); system(“pause“); ret

4、urn 0; 呵呵,什么也没有?是的。还记得字符串是怎么结束的吗?post.content “post.contenthello world “是个常量数组。但是字符串却是“” 。这章尽管非常简单,但是每个例子都经典之作,建议你每个都抄一遍,你能从代码中学到更多的东西。第二章 走过类型和表达式的迷宫这本书的第二章的内容是学习编程中最基础东西,任何一门语言都会告诉你他支持那些数据类型、那些运算、有那些特点、以及有那些不完善的东西。学习这些东西相对来说是单调了点,麻烦了点,但是只有通过了这座迷宫,你才能进入 C 这个神奇的世界。因此初学者的成功至少有一半来自“ 耐心” 。呵呵,准备好了吗?这章的内

5、容还是非常简单的,但是作者的字里行间隐藏了很多重要的信息,不加注意就会从我们的眼皮低下溜了去,下面将一一列出以示强调。变量和常量 很多人对于他们的区别很模糊,个人认为他们的主要区别在于是否分配内存空间,换句话说,就是是否存在左值。左值是什么?在第二章的从头到尾好像没找到这个名词,呵呵,你可以在附录中关于变量的条目中找到他,其实就是变量的地址,变量一旦被定义,左值就被确定了,一直到他的生存期结束。我们通常说的变量的值是指变量的右值。这才是我们能操作的对象。根据这个理论,那么就不难知道其实被 const 修饰的对象不是常量,他有左值,但是这里有个小麻烦,在本章的开头写明了被 const 修饰的是常

6、量(第二章章第二段有个()说明),我查看了原版,并没有这个补充说明,看来应该是译者的理解,在C 专家编程中的一个例子证明了我的想法是正确的,例子如下: #include “stdio.h” #include “stdlib.h” #define one 1 const int two = 2; int main() int ix = 1; switch( ix ) case one: printf( “this is 1“ );/*ok*/ break; case two: printf( “this is 2“ );/*error*/ system( “pause“ ); return 0;

7、 大家都知道,case 后面只能跟常量表达式,因此被 const 修饰的变量不是常量,只是变量的右值一般不能改变罢了。另外你也可以从上面感觉出#define 和 const 的区别。关于换码序列 这个更多地方叫转义字符,他们大多数是有一些特殊的功能的字符,在上篇笔记中你已经看到了他的一点威力,下面我们再看一段代码: #include “stdio.h“ #include “string.h“ #include “stdlib.h“ int main() int ix; ix = strlen( “post.contentabc“ ); printf( “this is %dn“, ix );

8、ix = strlen( “post.content7abc“ ); printf( “this is %dn“, ix ); system( “pause“ ); return 0; 你会发现,两个差不多的字符串长度完全不一样,什么回事呢?第一个我们可以理解:post.content是字符串结束符,因此其后的任何东西都不能算字符串的内容,因此长度为0。但是第二个呢?我们查了换码序列表就知道post.content7这个为一个字符,因此长度为 4。这个时候问题来了,编译器为什么没把post.content7理解为post.content07呢?如果这样的话长度也将为 0,我们又没人为的加分割符

9、号,呵呵,显然这个和编译器的具体实现相关,凭我们现有知识无法弄明白这点,姑且留着,等待“悟“ 的一天吧,相信我,这绝对是一种享受。关于+运算符 在很多教材上都有个看起来很经典的题目,其代码如下: #include “stdio.h“ #include “stdlib.h“ int main() int ix, iy; iy = 1; ix = ( iy+ ) + ( iy+ ) + ( iy+ ); printf( “this is %dn“, ix ); iy = 1; ix = ( +iy ) + ( iy+ ) + ( iy+ ); printf( “this is %dn“, ix )

10、; iy = 1; ix = ( +iy ) + ( +iy ) + ( iy+ ) ; printf( “this is %dn“, ix ); iy = 1; ix = ( +iy ) + ( +iy ) + ( +iy ) ; printf( “this is %dn“, ix ); system( “pause“ ); return 0; 呵呵,是不是很晕?这个本来无非为了说明先加后加的问题,这个地球人都知道,这里不加说明了,但是这样的程序本身就有很大的问题,编译器的运算并非一定是从左到右的(有些是按树的遍历来算的),因此你会发现不同的编译器结果会不一样,关于这个第二章的结尾有很完整的

11、解释,我就不再多说了,总之,这个测试本身就违背了语言的特性。第三章 当好机器的老板 无论什么时候我们都不该忘记我们是在学一门语言,而学语言的基本要求是:准确无误的用它来表示自己的意图,不仅要让机器读懂,也要让别人(只要他会 c 语言)读懂你的意思。记住,语言是用来交流的,不论是编程语言还是自然语言。现在让我们对这两个交流的对象分别作个分析,如何才能让他们明白你想干什么,打算怎么干。对于机器来说,我们要做的相对要简单点,编程语言的语法比自然语言要简单的多了,一切都由顺序、选择、循环三种结构复合而成,初学者要做的只是走一个“抄写改写模仿习惯”的过程而已。等这些语句成了你的习惯那就太好了,就像你说汉

12、语的时候不会去考虑你用的是陈述句还是感叹句,呵呵,(这个让我想起了我糟糕的英语,汗)。当然我们对机器要做的远远不止这些,让机器读懂这只是第一步而已,如何让机器按照我们的意思运行的更好、更快才是我们要追求的境界,当然,这个境界没有止境。得在经验中慢慢积累,下面只是提出几个个人的建议而已:尽量使用局部变量 因为 c 语言有个特点,在同个域中的变量必须定义在所有处理语句之前(分程序 除外),这意味着在程序开始的时候就必须分配好所有的静态空间,而很多数据在程序中用很少,因此我们需要减少这些不必要的开销,灵活运用分程序可以将这些对象进一步局部化,比较下面两段代码: Code1: #include “st

13、dio.h“ #include “stdlib.h“ int main() int ix; char c; scanf( “%c“, if( c = y) ix = 100; printf( “this is %d! n“, ix ); system( “pause“ ); return 0; Code2 #include “stdio.h“ #include “stdlib.h“ int main() char c; scanf( “%c“, if( c = y) int ix = 100; printf( “this is %d! n“, ix ); system( “pause“ );

14、return 0; 你会发现如果我们不输入y系统就没有必要为 ix 分配空间。注意和正视一些看起来像 bug 的语言特性 比如 switch 语句,可以说从 c 语言建立的那天起对他的争论就没有停止过,它的向下穿越给我们带来了不少麻烦。以至于在ISBN7-115-10627-4/ISBN 的第二章中把它说成是“ 多做之过“,但是我们发现有时候它的功能还是不可代替的,比如判断一个数是否属于某个离散集合: #include “stdio.h“ #include “stdlib.h“ int main() int i; while( scanf( “%d“, break; default : pri

15、ntf( “no!n“ ); break; system( “pause“ ); return 0; 呵呵,这个数列大家都熟悉,但是除了 switch 语句你能找到比他更简洁的表示方法吗?但这正是运用了语句的向下穿越性啊。goto 语句也有类似的情况,只要我们仔细研究,这些看起来很麻烦的东西都会变得非常美好。好了,对机器的交流我们就说到这儿吧。在下次笔记中我们将谈谈和人的交流程序的风格问题。第四章 关于程序风格的一点讨论。到目前为止,我们已经了解 c 程序的基本元素,在进入过程化程序设计之前,我个人认为该对编码习惯做个良好的开端。关于程序设计风格问题,严格来说是一个没答案的讨论,随着编码经验的

16、增加,我们在不同的阶段会有不同的认识,不同的出发点,本文要说的也只是笔者了两年来的编码体会,写出来的确需要勇气(毕竟在很多人眼里我没有这个资格),只是讨论的目的,绝无要误人子弟之意。 一个好的程序员写出来的代码不仅要让机器运行起来并实现想得到结果,而且要让任何一位懂 c 语言的人看了就明白这段代码是什么意思,而不是需要大量的注释和文档来帮助他搞懂你的意思(当然作为辅助还是必须的)。以下就是个人的一些体会: 合理利用空白字符,使得代码风格简洁清楚 下面这段代码,实在让人看起来费劲; #include “stdio.h” #include “stdlib.h” int main() int a21

17、,i,j; for(i=0;iptr = 0; p-size = 0; return p; status list_destroy( list *pev ) if( pev = 0 ) return ERR; delete_all( pev ); free( pev ); return OK; 按理说,函数不能返回指针,呵呵,这里有个很多初学者都误会的问题,返回局部对象的左值和局部对象的引用(后者是 c+中的说法) 被返回的确不可以,因为局部对象在函数的活动记录(即函数调用栈中)分配,函数一旦结束局部对象被回收,返回的将是无效地址。因此象下面这样的函数是错误的, int* f() int *p

18、, a; p = return p; 但是由 malloc 分配的是堆上分配的,他不会随着函数的结束而被回收。但是这样用要相当小心,必须防止内存泄漏。程序结束前必须 free 掉该空间。 下面就是完整的 list.c #include “stdio.h“ #include “stdlib.h“ /*严格来说此上面两处该用尖括号,由于网页显示不得已为之*/ #include “list.h“ list* list_init ( void ) list *p = ( list* )malloc( sizeof( list ) ); if( p = 0 ) return 0; p-ptr = 0;

19、p-size = 0; return p; status delete_all( list *pev ) int ix; if( pev = 0 ) return ERR; if( pev-size = 0 ) return ERR; for( ix = 0; ix size; +ix, +pev-ptr ) delete_node( pev, pev-ptr ); return OK; status insert_node( list *p, const type date ) list_node *pev = p-ptr; ; if( p = 0 ) return ERR; pev = f

20、ind_node( p, date ); if( pev = 0 ) type ia; printf( “输入要插入的数 n“ ); scanf( “%d“, add_node( p, ia ); else type ia; list_node *pv = ( list_node* )malloc( sizeof( list_node ) ); if( pev = 0 ) return ERR; printf( “输入要插入的数 n“ ); scanf( “%d“, pv-date = ia; pv-next = pev-next; pev-next = pv; p-size+; return

21、 OK; status list_print( const list *pev ) int ix; list_node *p = pev-ptr; if( pev = 0 ) return ERR; if( pev-size = 0 ) return OK; for( ix = 0; ix size; +ix ) printf( “%dt“, p-date ); p = p-next; printf( “n“ ); return OK; 第四步 连接各个接口 自己写个 main 函数,由于个人的调试方式不同,这里不给出代码。只要确保每个函数都能正常工作就行了。好了,到现在为止我们把一个数据结构

22、的实现走了一遍。当然,为了简单文字。笔者减少了很多 list 该有的功能。第六章 尽量利用能利用的资源 在上篇文字中,我们设计了一个非常简单的 list,在设计的过程运用了在本书第五、六章的知识,这些东西是 c 语言中最难的部分,学术方面的讨论随处可见,指针的用法和特性多得让人无法记住,个人认为最好的方法是多实践,在实践遇到的问题往往就是最常见的、最重要的知识点,至于那些特别的特性,等熟悉了那些常见的后也就不难理解他们了。 本书的第七。八两章所述的内容严格来说是不属于语言本身的东西,是的,我认为该这么说,这个关系到对”库” 的理解,库是什么?是别人已经写好的东西(类型、函数、常量等等),我们的

23、程序可以根据他们提供的接口调用就可,以节省我们开发的时间和精力,但是必须明白,不是没有库,我们就不能写东西了。第八章的内容就是告诉我们如何根据具体的 os 写出类似标准的 io 库,是的,库必须是系统相关的,当然你可以最大限度的保证他的可移植性(这正是标准库的成功之处)。 当然,对于大多数程序开发而言,库的运用可能是程序设计水平高低的最重要的指标之一,没有人会笨到放着的东西不用,而化费大量的时间去自己写一个(当然作为学习研究则正好相反)。有一次,一个网友跟我说标准 c+和 c 怎么也干不了,当我提出反对意见时,此人气势汹汹的质问:“你不用 WIN API 写个窗体给我看看!?” 。我无言了,因为要说的太多了, 比如:难道 API 是凭空出现的吗?难道我写不出 API 就可以说 c+和 c 无此能力吗?我无此荣幸,就算有,也不是片刻就可以拿出来给他证明的。因此我选择沉默,人类的任何成功都是建立在前人的基础上的,这样才有我们引以为傲的效率。 回到正题,标准库非常庞大( 别的也小不到那去) ,os 的系统调用也很多,对于这些我的建议是:记住常用的,别的用到的时候查手册之类的东西即可,比如,以 c 标准库为例,在本书附录 B 中提到的大多都需要记住。至于别的,大家可以去看看c 语言参考手册。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报