﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Cpp Fans-随笔分类-C/C++</title><link>http://www.cppblog.com/threesh/category/2670.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 May 2008 16:31:51 GMT</lastBuildDate><pubDate>Tue, 27 May 2008 16:31:51 GMT</pubDate><ttl>60</ttl><item><title>[转]学习C++的一点体会</title><link>http://www.cppblog.com/threesh/archive/2007/01/28/18104.html</link><dc:creator>Cpp Fans</dc:creator><author>Cpp Fans</author><pubDate>Sat, 27 Jan 2007 16:52:00 GMT</pubDate><guid>http://www.cppblog.com/threesh/archive/2007/01/28/18104.html</guid><wfw:comment>http://www.cppblog.com/threesh/comments/18104.html</wfw:comment><comments>http://www.cppblog.com/threesh/archive/2007/01/28/18104.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/threesh/comments/commentRss/18104.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/threesh/services/trackbacks/18104.html</trackback:ping><description><![CDATA[
		<p>我从去年11月份开始自学C++（本人现在做C#开发），现在把我这10来个月学习体会写出来和大家分享。</p>
		<p>1。关于要不要学习C++？（结论：要学，一定要学！）<br />如今在网上很多为要不要学C++争的不可开交，因为现在JAVA，C#，。NET都炒的很火，特别是JAVA，大有炸平庐山，停止地球转动之势。用林锐同志的话说，其实JAVA只是C++外甥，跑到舅舅身上撒了一泡尿而已。首先，我们从JAVA 的来历上来说，JAVA的设计初衷是用来给家用电器设计程序使用的，最初设计者想用C++，但觉得C++太复杂，就在C++的基础上做了一些简化，设计出了JAVA，它的设计思想是跨平台，所以必须先在运行平台上安装虚拟机，然后把源程序编译成中间语言在运行。这是一个优点，但我们说任意优点都是建立在缺点上的，JAVA的缺点就是运行速度慢，这对于某些系统来说是致命弱点。况且，JAVA中没有指针，对于制作系统软件来说，这更是无法饶恕的。再来看C++。C++产生于美国贝尔实验室，就是发明电话那个公司。设计初衷是用来改进C的开发效率，C是面向过程的语言，开发效率底，贝尔实验室有大量的C程序员，所以只要在开发效率上提高一点点，就可以节约数目庞大的成本。C是什么东西？是用来代替汇编编写操作系统的语言，用C++代替C，可以得出两个结论：第一，C++必须具有同C相当的执行速度；第二，C++必须比C具有较高的开发效率。执行速度方面，C++的设计者的思想就是在改进开发效率的同时尽量不增加C++的系统开销，当然有些地方非增加开销不可，也把开销控制在最小程度内。具非权威研究报告，C++比C的执行开销多出不到10%。开发效率方面，C++引进了面向对象机制，库机制，最大程度上实现了代码重用，这是软件开发人员的福音。C++在改进C的开发效率的同时，对C的缺陷做了一些修补。C的优点在C++中都得到了很好的保留，C的缺点在C++中都有了改进，有了更好的解决办法。而且，为了现有的大量C程序维护，C++还全面兼容了C。纵观当今程序语言家族，我觉得只有C可以C++相提并论，门当户对，其它语言都无法和C++相提并论。无论从什么角度来说，C++都算的上语言中的老大。<br />如今，网上有很多关于C++的争论，其实争论的人都是一些不知情的人，绝大多数是学校里的学生，我也曾经这样。在学校里的时候，不知道究竟应该学习什么，要是遇到好的老师还可以，遇到垃圾老师，垃圾学校那就更糟糕。如今，什么MCSE，CCNA，CIW等等认证漫天飞，把人搞的昏头昏脑，其实这都是认证公司炒的。社会上需要的是有真才实学的人，而不是需要证书。<br />我从大二开始学习编程，一开始学习VB，后来学习DELPHI，再后来学习C#，再后来学习C++，绕了个大圈子，最后还是绕回来了。而且重新学习数据结构，操作系统，学习软件工程，学习大学本科的基本课程，重新读外国的程序设计名著，而这些以前在大学是不屑一顾的。劝如今还在学校的师弟师妹们，努力学习C++。</p>
		<p>2。为什么要学习学习C++<br />1）C++的程序员身价普遍较高，当然，前提是你必须是高手。我所在的城市，那些公司根本就招不到合格的C++程序员，一方面C++程序员要求高，学习C++的人越来越少了。当然，怀着这个目的，你或许永远无法成为C++高手，但我把这个原因放在最前面，可以给大家一个很明确的激励，当你接触C++后，发现从学习中获得乐趣比高的工资更有动力；<br />2）C++的优势是用来开发大型软件，从中可以学到很多优秀的软件设计思想。C++不是软件开发的首选工具，一般说来，大多人更愿意学习和使用VB，为什么，简单。简单的另一个方面是功能的局限。微软公司恨不的所有人都学VB，只有他一家会C++。容易上手，大家都喜欢学，喜欢用，很多人拿一本200页的书，看个两三个星期，就觉得自己是个程序员了，可以开发软件了，而且觉得做出来的东西很不错。当软件规模大到一定程度的时候，其他语言就越来越无法驾驭，这时C++的优势就体现出来了。你说做个成绩管理系统，人事查询系统，用VB，DELPHI，C#，JAVA都行，但是例如银行，电信，保险，操作系统，数据仓库，图形处理，编译系统，较底层的软件时，其他工具几乎是无法完成的。就说C++的指针，JAVA没有，在遇到数据量交大的数据排序，搜索，动态内存分配时，它就没有办法了。所以说，学习C++，不仅仅是学到的一种语言，还学习了优秀的软件设计思想。<br />3）学习C++可以学习到计算机底层的理论，即使不是用C++开发，对计算机运行机制的理解，对建制稳定的系统，对运用其他语言，也是一种促进。这一点，我是在学习过程中体会到的，所以，要说出个大家可以接受的理由来较难，大家以后学习就知道了。</p>
		<p>3。怎样学习C++？<br />首先，我们必须承认，学习要讲究方法，有捷径。其次，我们还得承认，学习要下苦功，要务实。上小学的时候，书上有个故事，是关于王羲之学习书法的：王献之问他父亲王羲之，学习书法的秘诀是什么，他父亲把他带到后院，指着18口大水缸说，你如果把这里的水都写完了，就知道书法的秘诀在那里了。这个故事相信很多人都还记得。前几天看梁肇新（豪杰公司老板）的《高手箴言》，他说如果你如果愿意利用5年时间来成为高手，那么你只要两三年就会成为高手，如果你想一年成为高手，那么你5年也成不了高手。学习要切忌浮躁，要脚踏实地。我曾经很浮躁，结果一直呆在菜鸟堆里，当半年前我静下心来学习C++，才感觉有真正的进步。现在做WEB开发，虽然我从来不看WEB开发的书，但是我的同事遇到问题时，我经常能一下说出问题的所在。因为你看问题的角度变了。所以，学习C++的第一个方法是：切忌浮躁。其实学任何东西都一样，欲速则不达。从基本数据类型看起，从基本流程控制语句写起。<br />其次，教材很重要，要看经典名著。<br /><br />其次，教材很重要，要看经典名著，而且如果英语好，最好看原版英文教材。<br />经典之所以成为经典，是因为经历了考验沉淀下来的东西。去年9月份，当我打算转向C++的时候，曾向我一位同事咨询，他向我推荐了《C++编程思想》，还说叫我一定要读。当我读完前面三到四章的时候，就发觉自己找到了感觉。接下来，我一口气读完了整本书，当然其中很多东西还是无法真正理解，这是一本很深邃的书。废话少说，我现在把我自己看过的C++参考书籍列出来：</p>
		<p>1）《C++入门经典》，原名《The C++ Language Begeining》,作者Ivor Horton 此书浅显易懂极适合入门，书中包括最基本的程序设计知识，例如基本数据类型，流程控制语句，函数设计。即使没有任何程序设计基础的人，看着也不觉得累。书中一些很有特色的事例，能促进和加深读者的理解。但此书的代码风格实在有些糟糕。</p>
		<p>2）《C++编程思想》,原名《Thinking in C++》,作者Bruce Eckell, 此书的名气就不在这里说了.此书最新版本(第三版)开头部分增加了几章讲C语言的部分,然后把读者逐渐引向C++,在讨论语言的一个特性时,往往总是先讲解在C中的解决方法,然后讨论这中方法的局限和不足之处,再讨论C++中的解决方法.据我的感受,此书作者的初衷是引导C程序员走向C++,但后来发现大多数新生代程序员,非美国的程序员不一定懂C,于是就在第三版中加入了介绍C的部分. 此书最大的特点是, 作者善于透过语言现象,看看屏风后面究竟发生了什么(例如,显示出生成的汇编语言).消化好这本书，C++水平上一个大台阶；</p>
		<p>3）《C++高效编程》，原名《Effect C++》。此书重点探讨C++的一些技术死角，我只看过其中很少的一些章节，在此不作过多评论；</p>
		<p>4）《C++ Primer》，作者Stanley B.Lippman，此书还没有读过，接下来读这本书。我在网上找了一点对此书特点的描述：对C++基本概念和技术全面而且权威的阐述，对现代C++编程风格的强调，使本书成为C++初学者的最佳指南；对于中高级程序员，本书也是不可或缺的参考书。第4版不再强调低层编程技术，而把中心转向标准库的使用。书中很早就开始介绍标准库，示例也已经重新改写，充分利用了标准库设施。我们也对语言主题叙述的先后次序进行了重新编排，使讲解更加流畅；</p>
		<p>5）《C++编程语言》，原名《C++ Program Language》，作者乃C++的发明者被誉为C++之父的Bjarne Stroustrup，此书我只读了一部分，说实话，有些难。此书的作者就是C++的创始人，发明者，知识非常渊博，其思想深度远远在前面几位之上。如果你想知道C++究竟能做什么，C++那些希奇古怪的特性为什么那样设计，那你就去参考这本书。另外，阅读此书时，你还会为作者那种深邃的思想，博大的胸怀感觉到一种发自内的快乐，舒畅。书中还讲到了很多大型系统设计的方法和技巧。总之，不读此书，是作为程序员的一大遗憾。我建议先阅读《C++编程思想》，再参考此书。因为《C++编程思想》的作者说，他写这本书的目的就是为了大家能够参考《C++编程语言》这本书；</p>
		<p>6）《C++高质量编程》，作者林锐。此书不属于经典名著，但我也比较推荐这本书。作者不象国内其他作者那样迂腐功利，而是从一个程序员的角度，介绍他在以往开发过程中遇到的问题和积累的经验，这本书很薄，但其中的思想方法很有用。且语句诙谐幽默，阅读起来很轻松；</p>
		<p>任何一本书，都有他的可取之处；任何一本书，都无法解决在学习中遇到的所有问题；任何一本书，都无法替代人的智慧和经验。但是好的教材，可以起到好的指导效果，可以使学习少走弯路。但我不怎么建议看比较薄（600页以下）的书，因为对于C++来说，这样的篇幅根本就说不清楚，也不建议看国内作者的教材，你发现大多是从上面所说的书中抄下来的。</p>
		<p>4。C++和VC的区别<br />目前我们所说的C++，通常意义上指标准C++，就是美国C++标准委员会发布的C++。它定义了一些基本的语言规范语言特性，定义了一个框架，还有一个标准库。虽然产生于UNIX下，但它不属于某一个平台，某一个厂商，某一个编译器。它是一种统称，一种概念。VC是微软公司在WINDOWS平台下的一种开发工具，本质上和VB，C#没有什么区别，只是较之底层一些。VC支持标准C++，但不百分之百支持。一般来说，学习C++可以使用VC的编译环境，但是必须要使用标准库。还有其他一些C++编译器例如C++ BUIDER，就是Borland公司生产的WINDOWS下的C++编译器，GCC是LINUX下的常用的C++编译器。估计在苹果机下也有相应的C++编译器，因为C++处理图形系统是其特长。</p>
		<p>要学习C++，就不要从VC学起，学习VC无法学到真正的C++编程思想，而你只是学会了使用类库而已。C++的特性是什么？C++本质是什么？C++的精华是什么？我觉得总结成一句话：利用面向对象的思想，解决大型系统的开发问题。</p>
		<p>5。学习C++的重点<br />如果你学习过C或者了解C，那么在学习C++的时候更容易受C的影响，记住，C是面向过程的语，C++是面向对象的语言。如果你学习过C，那么学习C++的重点是掌握C++的新特性，C与C++的区别，C++的面向对象特性，尝试用C++的风格去编写程序，用C++的技术去解决问题。或许你认为C很不错，但在C++可能有更好的解决办法；</p>
		<p>如果你学习过JAVA，C#或DELPHI，那么你应该对面向对象机制很熟悉。但是，C++中的面向对象机制和上述几种语言有所区别，例如多重继承。最好尝试在没有用户界面的环境下编写程序，还有，指针是C++的精华之一，所以必须掌握；</p>
		<p>如果你没有编程基础，那就直接从C++学起，这样就没有其他语言的干扰和影响。祝贺你，一开始就接触了这样一种伟大的语言；</p>
		<p>我觉得，C++的重点可以用三个词来描述：指针，面向对象，标准库。</p>
		<p>最后，在这里同所有学习C++的程序员共勉，不要担心学习C++会被淘汰，我所在的单位还有大量的Informix程序员，而且日子过的很舒服。我小时候学书法，老师常对我说一句话就是：字写的好，哪怕拿一根筷子在嘴巴里咬几下，都写的好看，而不在于用什么笔。用C++之父Bjarne Stroustrup的话来说：只要你在使用电脑，你就直接或间接使用了C++。</p>
		<p>让我们共同学习，共同进步，相互交流，相互促进。</p>
<img src ="http://www.cppblog.com/threesh/aggbug/18104.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/threesh/" target="_blank">Cpp Fans</a> 2007-01-28 00:52 <a href="http://www.cppblog.com/threesh/archive/2007/01/28/18104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[轉]C语言程序设计基础之文件</title><link>http://www.cppblog.com/threesh/archive/2006/10/27/14273.html</link><dc:creator>Cpp Fans</dc:creator><author>Cpp Fans</author><pubDate>Fri, 27 Oct 2006 03:03:00 GMT</pubDate><guid>http://www.cppblog.com/threesh/archive/2006/10/27/14273.html</guid><wfw:comment>http://www.cppblog.com/threesh/comments/14273.html</wfw:comment><comments>http://www.cppblog.com/threesh/archive/2006/10/27/14273.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/threesh/comments/commentRss/14273.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/threesh/services/trackbacks/14273.html</trackback:ping><description><![CDATA[
		<font size="2">　所谓“文件”是指一组相关数据的有序集合。 这个数据集有一个名称，叫做文件名。 实际上在前面的各章中我们已经多次使用了文件，例如源程序文件、目标文件、可执行文件、库文件 (头文件)等。文件通常是驻留在外部介质(如磁盘等)上的， 在使用时才调入内存中来。从不同的角度可对文件作不同的分类。从用户的角度看，文件可分为普通文件和设备文件两种。 <br /><br />　　普通文件是指驻留在磁盘或其它外部介质上的一个有序数据集，可以是源文件、目标文件、可执行程序； 也可以是一组待输入处理的原始数据，或者是一组输出的结果。对于源文件、目标文件、 可执行程序可以称作程序文件，对输入输出数据可称作数据文件。<br /><br />　　设备文件是指与主机相联的各种外部设备，如显示器、打印机、键盘等。在操作系统中，把外部设备也看作是一个文件来进行管理，把它们的输入、输出等同于对磁盘文件的读和写。 通常把显示器定义为标准输出文件， 一般情况下在屏幕上显示有关信息就是向标准输出文件输出。如前面经常使用的printf,putchar 函数就是这类输出。键盘通常被指定标准的输入文件， 从键盘上输入就意味着从标准输入文件上输入数据。scanf,getchar函数就属于这类输入。 <br /><br />　　从文件编码的方式来看，文件可分为ASCII码文件和二进制码文件两种。<br /><br />　　ASCII文件也称为文本文件，这种文件在磁盘中存放时每个字符对应一个字节，用于存放对应的ASCII码。例如，数5678的存储形式为：<br />ASC码： 　00110101 00110110 00110111 00111000<br />　　　　　↓ 　　　　↓　　　　↓ 　　　↓<br />十进制码： 5　　　　　6　　　　7　　　　8 共占用4个字节。ASCII码文件可在屏幕上按字符显示， 例如源程序文件就是ASCII文件，用DOS命令TYPE可显示文件的内容。 由于是按字符显示，因此能读懂文件内容。<br /><br />　　二进制文件是按二进制的编码方式来存放文件的。 例如， 数5678的存储形式为： 00010110 00101110只占二个字节。二进制文件虽然也可在屏幕上显示， 但其内容无法读懂。C系统在处理这些文件时，并不区分类型，都看成是字符流，按字节进行处理。 输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也把这种文件称作“流式文件”。<br /><br />　　本章讨论流式文件的打开、关闭、读、写、 定位等各种操作。文件指针在C语言中用一个指针变量指向一个文件， 这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。 定义说明文件指针的一般形式为： FILE* 指针变量标识符； 其中FILE应为大写，它实际上是由系统定义的一个结构， 该结构中含有文件名、文件状态和文件当前位置等信息。 在编写源程序时不必关心FILE结构的细节。例如：FILE *fp； 表示fp是指向FILE结构的指针变量，通过fp 即可找存放某个文件信息的结构变量，然后按结构变量提供的信息找到该文件， 实施对文件的操作。习惯上也笼统地把fp称为指向一个文件的指针。文件的打开与关闭文件在进行读写操作之前要先打开，使用完毕要关闭。 所谓打开文件，实际上是建立文件的各种有关信息， 并使文件指针指向该文件，以便进行其它操作。关闭文件则断开指针与文件之间的联系，也就禁止再对该文件进行操作。<br /><br />　　在C语言中，文件操作都是由库函数来完成的。 在本章内将介绍主要的文件操作函数。<br /><br />　　文件打开函数fopen<br /><br />　　fopen函数用来打开一个文件，其调用的一般形式为： 文件指针名=fopen(文件名，使用文件方式) 其中，“文件指针名”必须是被说明为FILE 类型的指针变量，“文件名”是被打开文件的文件名。 “使用文件方式”是指文件的类型和操作要求。“文件名”是字符串常量或字符串数组。例如： <br /><br /></font>
		<table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1">
				<tbody>
						<tr>
								<td>FILE *fp；<br />fp=("file a","r");</td>
						</tr>
				</tbody>
		</table>
		<br />　　其意义是在当前目录下打开文件file a， 只允许进行“读”操作，并使fp指向该文件。<br /><br />　　又如：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>FILE *fphzk<br />fphzk=("c:\\hzk16',"rb")</td></tr></tbody></table><br />　　其意义是打开C驱动器磁盘的根目录下的文件hzk16， 这是一个二进制文件，只允许按二进制方式进行读操作。两个反斜线“\\ ”中的第一个表示转义字符，第二个表示根目录。使用文件的方式共有12种，下面给出了它们的符号和意义。 <br /><br />文件使用方式 　　　　　　　意 义<br />“rt”　　　　　　只读打开一个文本文件，只允许读数据 <br />“wt”　　　　　　只写打开或建立一个文本文件，只允许写数据<br />“at”　　　　　　追加打开一个文本文件，并在文件末尾写数据<br />“rb”　　　　　　只读打开一个二进制文件，只允许读数据<br />“wb”　　　　 　 只写打开或建立一个二进制文件，只允许写数据<br />“ab” 　　　　 　追加打开一个二进制文件，并在文件末尾写数据<br />“rt+”　　　　　 读写打开一个文本文件，允许读和写<br />“wt+”　　　　　 读写打开或建立一个文本文件，允许读写<br />“at+”　　　　　 读写打开一个文本文件，允许读，或在文件末追加数 据<br />“rb+”　　　　　 读写打开一个二进制文件，允许读和写 <br />“wb+”　　　　　 读写打开或建立一个二进制文件，允许读和写<br />“ab+” 　　　　　读写打开一个二进制文件，允许读，或在文件末追加数据<br /><br />　　对于文件使用方式有以下几点说明：<br /><br />　　1. 文件使用方式由r,w,a,t,b，+六个字符拼成，各字符的含义是：<br /><br />　　r(read): 读<br />　　w(write): 写<br />　　a(append): 追加<br />　　t(text): 文本文件，可省略不写<br />　　b(banary): 二进制文件<br />　　+: 读和写<br /><br />　　2. 凡用“r”打开一个文件时，该文件必须已经存在， 且只能从该文件读出。<br /><br />　　3. 用“w”打开的文件只能向该文件写入。 若打开的文件不存在，则以指定的文件名建立该文件，若打开的文件已经存在，则将该文件删去，重建一个新文件。<br /><br />　　4. 若要向一个已存在的文件追加新的信息，只能用“a ”方式打开文件。但此时该文件必须是存在的，否则将会出错。<br /><br />　　5. 在打开一个文件时，如果出错，fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作，并作相应的处理。因此常用以下程序段打开文件：<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>if((fp=fopen("c:\\hzk16","rb")==NULL)<br />{<br />printf("\nerror on open c:\\hzk16 file!");<br />getch();<br />exit(1);<br />}</td></tr></tbody></table><br />　　这段程序的意义是，如果返回的指针为空，表示不能打开C盘根目录下的hzk16文件，则给出提示信息“error on open c:\ hzk16file!”，下一行getch()的功能是从键盘输入一个字符，但不在屏幕上显示。在这里，该行的作用是等待， 只有当用户从键盘敲任一键时，程序才继续执行， 因此用户可利用这个等待时间阅读出错提示。敲键后执行exit(1)退出程序。<br /><br />　　6. 把一个文本文件读入内存时，要将ASCII码转换成二进制码， 而把文件以文本方式写入磁盘时，也要把二进制码转换成ASCII码，因此文本文件的读写要花费较多的转换时间。对二进制文件的读写不存在这种转换。<br /><br />　　7. 标准输入文件(键盘)，标准输出文件(显示器 )，标准出错输出(出错信息)是由系统打开的，可直接使用。文件关闭函数ｆCｌｏｓｅ文件一旦使用完毕，应用关闭文件函数把文件关闭， 以避免文件的数据丢失等错误。<br /><br />　　fclose函数<br /><br />　　调用的一般形式是： fclose(文件指针)； 例如：<br /><br />　　fclose(fp); 正常完成关闭文件操作时，fclose函数返回值为0。如返回非零值则表示有错误发生。文件的读写对文件的读和写是最常用的文件操作。 <br /><br />　　在C语言中提供了多种文件读写的函数： <br /><br />　　·字符读写函数 ：fgetc和fputc<br /><br />　　·字符串读写函数：fgets和fputs<br /><br />　　·数据块读写函数：freed和fwrite<br /><br />　　·格式化读写函数：fscanf和fprinf<br /><br />　　下面分别予以介绍。使用以上函数都要求包含头文件stdio.h。字符读写函数ｆｇｅｔC和ｆｐｕｔC字符读写函数是以字符(字节)为单位的读写函数。 每次可从文件读出或向文件写入一个字符。<br /><br /><p></p>　　<strong>一、读字符函数fgetc</strong><br /><br />　　fgetc函数的功能是从指定的文件中读一个字符，函数调用的形式为： 字符变量=fgetc(文件指针)； 例如：ch=fgetc(fp);其意义是从打开的文件fp中读取一个字符并送入ch中。<br /><br />　　对于fgetc函数的使用有以下几点说明：<br /><br />　　1. 在fgetc函数调用中，读取的文件必须是以读或读写方式打开的。<br /><br />　　2. 读取字符的结果也可以不向字符变量赋值，例如：fgetc(fp);但是读出的字符不能保存。<br /><br />　　3. 在文件内部有一个位置指针。用来指向文件的当前读写字节。在文件打开时，该指针总是指向文件的第一个字节。使用fgetc 函数后， 该位置指针将向后移动一个字节。 因此可连续多次使用fgetc函数，读取多个字符。 应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的，须在程序中定义说明，只要不重新赋值，文件指针的值是不变的。文件内部的位置指针用以指示文件内部的当前读写位置，每读写一次，该指针均向后移动，它不需在程序中定义说明，而是由系统自动设置的。<br /><br />　　[例10.1]读入文件e10-1.c，在屏幕上输出。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />main()<br />{<br />FILE *fp;<br />char ch;<br />if((fp=fopen("e10_1.c","rt"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />ch=fgetc(fp);<br />while (ch!=EOF)<br />{<br />putchar(ch);<br />ch=fgetc(fp);<br />}<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　本例程序的功能是从文件中逐个读取字符，在屏幕上显示。 程序定义了文件指针fp,以读文本文件方式打开文件“e10_1.c”， 并使fp指向该文件。如打开文件出错， 给出提示并退出程序。程序第12行先读出一个字符，然后进入循环， 只要读出的字符不是文件结束标志(每个文件末有一结束标志EOF)就把该字符显示在屏幕上，再读入下一字符。每读一次，文件内部的位置指针向后移动一个字符，文件结束时，该指针指向EOF。执行本程序将显示整个文件。<br /><br />　　<strong>二、写字符函数fputc</strong><br /><br />　　fputc函数的功能是把一个字符写入指定的文件中，函数调用的 形式为： fputc(字符量，文件指针)； 其中，待写入的字符量可以是字符常量或变量，例如：fputc('a',fp);其意义是把字符a写入fp所指向的文件中。<br /><br />　　对于fputc函数的使用也要说明几点：<br /><br />　　1. 被写入的文件可以用、写、读写，追加方式打开，用写或读写方式打开一个已存在的文件时将清除原有的文件内容，写入字符从文件首开始。如需保留原有文件内容，希望写入的字符以文件末开始存放，必须以追加方式打开文件。被写入的文件若不存在，则创建该文件。<br /><br />　　2. 每写入一个字符，文件内部位置指针向后移动一个字节。<br /><br />　　3. fputc函数有一个返回值，如写入成功则返回写入的字符， 否则返回一个EOF。可用此来判断写入是否成功。<br /><br />　　[例10.2]从键盘输入一行字符，写入一个文件， 再把该文件内容读出显示在屏幕上。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />main()<br />{<br />FILE *fp;<br />char ch;<br />if((fp=fopen("string","wt+"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />printf("input a string:\n");<br />ch=getchar();<br />while (ch!='\n')<br />{<br />fputc(ch,fp);<br />ch=getchar();<br />}<br />rewind(fp);<br />ch=fgetc(fp);<br />while(ch!=EOF)<br />{<br />putchar(ch);<br />ch=fgetc(fp);<br />}<br />printf("\n");<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　程序中第6行以读写文本文件方式打开文件string。程序第13行从键盘读入一个字符后进入循环，当读入字符不为回车符时， 则把该字符写入文件之中，然后继续从键盘读入下一字符。 每输入一个字符，文件内部位置指针向后移动一个字节。写入完毕， 该指针已指向文件末。如要把文件从头读出，须把指针移向文件头， 程序第19行rewind函数用于把fp所指文件的内部位置指针移到文件头。 第20至25行用于读出文件中的一行内容。<br /><br />　　[例10.3]把命令行参数中的前一个文件名标识的文件， 复制到后一个文件名标识的文件中， 如命令行中只有一个文件名则把该文件写到标准输出文件(显示器)中。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />main(int argc,char *argv[])<br />{<br />FILE *fp1,*fp2;<br />char ch;<br />if(argc==1)<br />{<br />printf("have not enter file name strike any key exit");<br />getch();<br />exit(0);<br />}<br />if((fp1=fopen(argv[1],"rt"))==NULL)<br />{<br />printf("Cannot open %s\n",argv[1]);<br />getch();<br />exit(1);<br />}<br />if(argc==2) fp2=stdout;<br />else if((fp2=fopen(argv[2],"wt+"))==NULL)<br />{<br />printf("Cannot open %s\n",argv[1]);<br />getch();<br />exit(1);<br />}<br />while((ch=fgetc(fp1))!=EOF)<br />fputc(ch,fp2);<br />fclose(fp1);<br />fclose(fp2);<br />}</td></tr></tbody></table><br />　　本程序为带参的main函数。程序中定义了两个文件指针 fp1 和fp2，分别指向命令行参数中给出的文件。如命令行参数中没有给出文件名，则给出提示信息。程序第18行表示如果只给出一个文件名，则使fp2指向标准输出文件(即显示器)。程序第25行至28行用循环语句逐个读出文件1中的字符再送到文件2中。再次运行时，给出了一个文件名(由例10.2所建立的文件)， 故输出给标准输出文件stdout，即在显示器上显示文件内容。第三次运行，给出了二个文件名，因此把string中的内容读出，写入到OK之中。可用DOS命令type显示OK的内容：<br /><br /><p></p>　　<strong>字符串读写函数fgets和fputs</strong><br /><br />　　一、读字符串函数fgets函数的功能是从指定的文件中读一个字符串到字符数组中，函数调用的形式为： fgets(字符数组名，n，文件指针)； 其中的n是一个正整数。表示从文件中读出的字符串不超过 n-1个字符。在读入的最后一个字符后加上串结束标志'\0'。例如：fgets(str,n,fp);的意义是从fp所指的文件中读出n-1个字符送入字符数组str中。<br /><br />　　[例10.4]从e10_1.c文件中读入一个含10个字符的字符串。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />main()<br />{<br />FILE *fp;<br />char str[11];<br />if((fp=fopen("e10_1.c","rt"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />fgets(str,11,fp);<br />printf("%s",str);<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　本例定义了一个字符数组str共11个字节，在以读文本文件方式打开文件e101.c后，从中读出10个字符送入str数组，在数组最后一个单元内将加上'\0'，然后在屏幕上显示输出str数组。输出的十个字符正是例10.1程序的前十个字符。<br /><br />　　对fgets函数有两点说明：<br /><br />　　1. 在读出n-1个字符之前，如遇到了换行符或EOF，则读出结束。<br /><br />　　2. fgets函数也有返回值，其返回值是字符数组的首地址。<br /><br />　　二、写字符串函数fputs<br /><br />　　fputs函数的功能是向指定的文件写入一个字符串，其调用形式为： fputs(字符串，文件指针) 其中字符串可以是字符串常量，也可以是字符数组名， 或指针 变量，例如：<br /><br />fputs(“abcd“，fp)；<br /><br />　　其意义是把字符串“abcd”写入fp所指的文件之中。[例10.5]在例10.2中建立的文件string中追加一个字符串。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />main()<br />{<br />FILE *fp;<br />char ch,st[20];<br />if((fp=fopen("string","at+"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />printf("input a string:\n");<br />scanf("%s",st);<br />fputs(st,fp);<br />rewind(fp);<br />ch=fgetc(fp);<br />while(ch!=EOF)<br />{<br />putchar(ch);<br />ch=fgetc(fp);<br />}<br />printf("\n");<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　本例要求在string文件末加写字符串，因此，在程序第6行以追加读写文本文件的方式打开文件string 。 然后输入字符串， 并用fputs函数把该串写入文件string。在程序15行用rewind函数把文件内部位置指针移到文件首。 再进入循环逐个显示当前文件中的全部内容。<br /><br /><p></p>　　<strong>数据块读写函数fread和fwrite</strong><br /><br />　　C语言还提供了用于整块数据的读写函数。 可用来读写一组数据，如一个数组元素，一个结构变量的值等。读数据块函数调用的一般形式为： fread(buffer,size,count,fp); 写数据块函数调用的一般形式为： fwrite(buffer,size,count,fp); 其中buffer是一个指针，在fread函数中，它表示存放输入数据的首地址。在fwrite函数中，它表示存放输出数据的首地址。 size 表示数据块的字节数。count 表示要读写的数据块块数。fp 表示文件指针。<br /><br />　　例如：<br /><br />fread(fa,4,5,fp); 其意义是从fp所指的文件中，每次读4个字节(一个实数)送入实数组fa中，连续读5次，即读5个实数到fa中。<br /><br />　　[例10.6]从键盘输入两个学生数据，写入一个文件中， 再读出这两个学生的数据显示在屏幕上。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />struct stu<br />{<br />char name[10];<br />int num;<br />int age;<br />char addr[15];<br />}boya[2],boyb[2],*pp,*qq;<br />main()<br />{<br />FILE *fp;<br />char ch;<br />int i;<br />pp=boya;<br />qq=boyb;<br />if((fp=fopen("stu_list","wb+"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />printf("\ninput data\n");<br />for(i=0;i&lt;2;i++,pp++)<br />scanf("%s%d%d%s",pp-&gt;name,&amp;pp-&gt;num,&amp;pp-&gt;age,pp-&gt;addr);<br />pp=boya;<br />fwrite(pp,sizeof(struct stu),2,fp);<br />rewind(fp);<br />fread(qq,sizeof(struct stu),2,fp);<br />printf("\n\nname\tnumber age addr\n");<br />for(i=0;i&lt;2;i++,qq++)<br />printf("%s\t%5d%7d%s\n",qq-&gt;name,qq-&gt;num,qq-&gt;age,qq-&gt;addr);<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　本例程序定义了一个结构stu,说明了两个结构数组boya和 boyb以及两个结构指针变量pp和qq。pp指向boya,qq指向boyb。程序第16行以读写方式打开二进制文件“stu_list”，输入二个学生数据之后，写入该文件中， 然后把文件内部位置指针移到文件首，读出两块学生数据后，在屏幕上显示。<br /><br /><p></p>　　<strong>格式化读写函数fscanf和fprintf</strong><br /><br />　　fscanf函数，fprintf函数与前面使用的scanf和printf 函数的功能相似，都是格式化读写函数。 两者的区别在于 fscanf 函数和fprintf函数的读写对象不是键盘和显示器，而是磁盘文件。这两个函数的调用格式为： fscanf(文件指针，格式字符串，输入表列)； fprintf(文件指针，格式字符串，输出表列)； 例如：<br /><br />　　fscanf(fp,"%d%s",&amp;i,s);<br />　　fprintf(fp,"%d%c",j,ch); <br /><br />　　用fscanf和fprintf函数也可以完成例10.6的问题。修改后的程序如例10.7所示。<br /><br />　　[例10.7]<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />struct stu<br />{<br />char name[10];<br />int num;<br />int age;<br />char addr[15];<br />}boya[2],boyb[2],*pp,*qq;<br />main()<br />{<br />FILE *fp;<br />char ch;<br />int i;<br />pp=boya;<br />qq=boyb;<br />if((fp=fopen("stu_list","wb+"))==NULL)<br />{<br />printf("Cannot open file strike any key exit!");<br />getch();<br />exit(1);<br />}<br />printf("\ninput data\n");<br />for(i=0;i&lt;2;i++,pp++)<br />scanf("%s%d%d%s",pp-&gt;name,&amp;pp-&gt;num,&amp;pp-&gt;age,pp-&gt;addr);<br />pp=boya;<br />for(i=0;i&lt;2;i++,pp++)<br />fprintf(fp,"%s %d %d %s\n",pp-&gt;name,pp-&gt;num,pp-&gt;age,pp-&gt;<br />addr);<br />rewind(fp);<br />for(i=0;i&lt;2;i++,qq++)<br />fscanf(fp,"%s %d %d %s\n",qq-&gt;name,&amp;qq-&gt;num,&amp;qq-&gt;age,qq-&gt;addr);<br />printf("\n\nname\tnumber age addr\n");<br />qq=boyb;<br />for(i=0;i&lt;2;i++,qq++)<br />printf("%s\t%5d %7d %s\n",qq-&gt;name,qq-&gt;num, qq-&gt;age,<br />qq-&gt;addr);<br />fclose(fp);<br />}</td></tr></tbody></table><br />　　与例10.6相比，本程序中fscanf和fprintf函数每次只能读写一个结构数组元素，因此采用了循环语句来读写全部数组元素。 还要注意指针变量pp,qq由于循环改变了它们的值，因此在程序的25和32行分别对它们重新赋予了数组的首地址。<br /><br />　　文件的随机读写<br /><br />　　前面介绍的对文件的读写方式都是顺序读写， 即读写文件只能从头开始，顺序读写各个数据。 但在实际问题中常要求只读写文件中某一指定的部分。 为了解决这个问题可移动文件内部的位置指针到需要读写的位置，再进行读写，这种读写称为随机读写。 实现随机读写的关键是要按要求移动位置指针，这称为文件的定位。文件定位移动文件内部位置指针的函数主要有两个， 即 rewind 函数和fseek函数。<br /><br />　　rewind函数前面已多次使用过，其调用形式为： rewind(文件指针)； 它的功能是把文件内部的位置指针移到文件首。 下面主要介绍<br />fseek函数。<br /><br />　　fseek函数用来移动文件内部位置指针，其调用形式为： fseek(文件指针，位移量，起始点)； 其中：“文件指针”指向被移动的文件。 “位移量”表示移动的字节数，要求位移量是long型数据，以便在文件长度大于64KB 时不会出错。当用常量表示位移量时，要求加后缀“L”。“起始点”表示从何处开始计算位移量，规定的起始点有三种：文件首，当前位置和文件尾。<br /><br />　　其表示方法如表10.2。 <br /><br />起始点 　　　表示符号 　　　数字表示<br />──────────────────────────<br />文件首 　　　SEEK—SET　　　　0<br />当前位置 　　SEEK—CUR　　　　1<br />文件末尾 　　SEEK—END 　　　 2<br /><br />　　例如：<br /><br />　　fseek(fp,100L,0);其意义是把位置指针移到离文件首100个字节处。还要说明的是fseek函数一般用于二进制文件。在文本文件中由于要进行转换，故往往计算的位置会出现错误。文件的随机读写在移动位置指针之后， 即可用前面介绍的任一种读写函数进行读写。由于一般是读写一个数据据块，因此常用fread和fwrite函数。下面用例题来说明文件的随机读写。<br /><br />　　[例10.8]在学生文件stu list中读出第二个学生的数据。<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>#include&lt;stdio.h&gt;<br />struct stu<br />{<br />　char name[10];<br />　int num;<br />　int age;<br />　char addr[15];<br />}boy,*qq;<br />main()<br />{<br />　FILE *fp;<br />　char ch;<br />　int i=1;<br />　qq=&amp;boy;<br />　if((fp=fopen("stu_list","rb"))==NULL)<br />　{<br />　　printf("Cannot open file strike any key exit!");<br />　　getch();<br />　　exit(1);<br />　}<br />　rewind(fp);<br />　fseek(fp,i*sizeof(struct stu),0);<br />　fread(qq,sizeof(struct stu),1,fp);<br />　printf("\n\nname\tnumber age addr\n");<br />　printf("%s\t%5d %7d %s\n",qq-&gt;name,qq-&gt;num,qq-&gt;age,<br />　qq-&gt;addr);<br />}</td></tr></tbody></table><br />　　文件stu_list已由例10.6的程序建立，本程序用随机读出的方法读出第二个学生的数据。程序中定义boy为stu类型变量，qq为指向boy的指针。以读二进制文件方式打开文件，程序第22行移动文件位置指针。其中的i值为1，表示从文件头开始，移动一个stu类型的长度， 然后再读出的数据即为第二个学生的数据。<br /><br />　　文件检测函数<br /><br />　　C语言中常用的文件检测函数有以下几个。<br /><br />　　一、文件结束检测函数feof函数调用格式： feof(文件指针)； <br /><br />　　功能：判断文件是否处于文件结束位置，如文件结束，则返回值为1，否则为0。<br /><br />　　二、读写文件出错检测函数ferror函数调用格式： ferror(文件指针)； <br /><br />　　功能：检查文件在用各种输入输出函数进行读写时是否出错。 如ferror返回值为0表示未出错，否则表示有错。<br /><br />　　三、文件出错标志和文件结束标志置0函数clearerr函数调用格式： clearerr(文件指针); <br /><br />　　功能：本函数用于清除出错标志和文件结束标志，使它们为0值。<br /><br />　　C库文件<br /><br />　　C系统提供了丰富的系统文件，称为库文件，C的库文件分为两类，一类是扩展名为".h"的文件，称为头文件， 在前面的包含命令中我们已多次使用过。在".h"文件中包含了常量定义、 类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库，包括了各种函数的目标代码，供用户在程序中调用。 通常在程序中调用一个库函数时，要在调用之前包含该函数原型所在的".h" 文件。<br /><br />　　在附录中给出了全部库函数。<br /><br />ALLOC.H 　　　说明内存管理函数(分配、释放等)。<br />ASSERT.H 　 　定义 assert调试宏。<br />BIOS.H 　　 　说明调用IBM—PC ROM BIOS子程序的各个函数。<br />CONIO.H 　　　说明调用DOS控制台I/O子程序的各个函数。<br />CTYPE.H 　　　包含有关字符分类及转换的名类信息(如 isalpha和toascii等)。<br />DIR.H 　　　　包含有关目录和路径的结构、宏定义和函数。<br />DOS.H 　　　　定义和说明MSDOS和8086调用的一些常量和函数。<br />ERRON.H 　　　定义错误代码的助记符。<br />FCNTL.H 　　　定义在与open库子程序连接时的符号常量。<br />FLOAT.H 　　　包含有关浮点运算的一些参数和函数。<br />GRAPHICS.H 　 说明有关图形功能的各个函数，图形错误代码的常量定义，正对不同驱动程序的各种颜色值，及函数用到的一些特殊结构。<br />IO.H 　　　　 包含低级I/O子程序的结构和说明。<br />LIMIT.H 　　　包含各环境参数、编译时间限制、数的范围等信息。<br />MATH.H 　　　 说明数学运算函数，还定了 HUGE VAL 宏， 说明了matherr和matherr子程序用到的特殊结构。<br />MEM.H 　　　　说明一些内存操作函数(其中大多数也在STRING.H 中说明)。<br />PROCESS.H 　　说明进程管理的各个函数，spawn…和EXEC …函数的结构说明。<br />SETJMP.H 　　 定义longjmp和setjmp函数用到的jmp buf类型， 说明这两个函数。<br />SHARE.H 　　　定义文件共享函数的参数。<br />SIGNAL.H 　　 定义SIG[ZZ(Z] [ZZ)]IGN和SIG[ZZ(Z] [ZZ)]DFL常量，说明rajse和signal两个函数。<br />STDARG.H 　　 定义读函数参数表的宏。(如vprintf,vscarf函数)。<br />STDDEF.H 　　 定义一些公共数据类型和宏。<br />STDIO.H 　　　定义Kernighan和Ritchie在Unix System V 中定义的标准和扩展的类型和宏。还定义标准I/O 预定义流：stdin,stdout和stderr，说明 I/O流子程序。<br />STDLIB.H 　　 说明一些常用的子程序：转换子程序、搜索/ 排序子程序等。<br />STRING.H 　　 说明一些串操作和内存操作函数。<br />SYS\STAT.H 　 定义在打开和创建文件时用到的一些符号常量。<br />SYS\TYPES.H 　说明ftime函数和timeb结构。<br />SYS\TIME.H 　 定义时间的类型time[ZZ(Z] [ZZ)]t。<br />TIME.H 　　　 定义时间转换子程序asctime、localtime和gmtime的结构，ctime、 difftime、 gmtime、 localtime和stime用到的类型，并提供这些函数的原型。<br />VALUE.H 　　　定义一些重要常量， 包括依赖于机器硬件的和为与Unix System V相兼容而说明的一些常量，包括浮点和双精度值的范围。<br /><img src ="http://www.cppblog.com/threesh/aggbug/14273.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/threesh/" target="_blank">Cpp Fans</a> 2006-10-27 11:03 <a href="http://www.cppblog.com/threesh/archive/2006/10/27/14273.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++程序设计之四书五经[转]</title><link>http://www.cppblog.com/threesh/archive/2006/10/20/13899.html</link><dc:creator>Cpp Fans</dc:creator><author>Cpp Fans</author><pubDate>Fri, 20 Oct 2006 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/threesh/archive/2006/10/20/13899.html</guid><wfw:comment>http://www.cppblog.com/threesh/comments/13899.html</wfw:comment><comments>http://www.cppblog.com/threesh/archive/2006/10/20/13899.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/threesh/comments/commentRss/13899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/threesh/services/trackbacks/13899.html</trackback:ping><description><![CDATA[C++程序设计之四书五经（上篇） <br /><br />C++是一门广泛用于工业软件研发的大型语言。它自身的复杂性和解决现实问题的能力，使其极具学术研究价值和工业价值。和C语言一样，C++已经在许多重要的领域大获成功。 <br /><br />然而，一个不可否认的现实是，在低阶程序设计领域，C++挤压着C同时也在承受着C的强烈反弹，而在高阶程序设计领域，Java和C#正在不断蚕食着C++的地盘。也许C++与C合为一体永远都是一个梦想，也许Java和C#的狂潮终将迫使C++回归本位 — 回到它有着根本性优势的开发领域：低级系统程序设计、高级大规模高性能应用设计、嵌入式程序设计以及数值科学计算等。果真如此，我认为这未尝不是一件好事。 <br /><br />C++吸引如此之多的智力投入，以至于这个领域的优秀作品，包括重量级的软件产品、程序库以及书籍等，数不胜数。文题“C++程序设计之四书五经”一个不太严格的含义是：C++程序设计之四书 ⅹ 五经。是的，在本文（及其下篇）中，我将分门别类推荐20多本C++好书，你可以根据自己的需要选读。 <br /><br />TCPL和D&amp;E <br /><br />TCPL和D&amp;E分别是《The C++ Programming Language》和《The Design and Evolution of C++》的简称，均出自Bjarne Stroustrup之手。我将它们单列出来，首先是因为Bjarne是C++语言的创建者，然后是因为比“首先”那个原因更重要的原因：这两本书是C++领域毋庸置疑的杰作。说它们是C++语言圣经，并不为过。 <br /><br />Bjarne Stroustrup, The C++ Programming Language (Special 3rd Edition) <br />《C++程序设计语言（特别版）》，机械工业出版社 <br />《C++程序设计语言（特别版）（英文影印版）》，高等教育出版社 <br /><br />迄今为止，TCPL是除了C++标准文献之外最权威的C++参考手册。和大多数人的看法不大一样，我认为Bjarne的文字语言并不逊色于他所创建的程序语言，至少我喜欢这种学院气息浓厚的作品。本书对C++语言的描述轮廓鲜明、直截了当。它从C++语言创建者的角度来观察C++，这是任何别的作者和书籍做不到的 — 没有任何人比Bjarne自己更清楚该怎么来使用C++。 <br /><br />这是一本严肃的著作，以中、高级C++开发人员为目标读者。如果你是一名有经验的C++程序员，需要了解更加本质的C++知识，本书正是为你而写。它不是那种让你看了会不断窃喜的小书，需要用心体会，反复咀嚼。在阅读过程中，请特别留心Bjarne先生强调了什么，又对什么一语带过。我个人比较喜欢这本书的第四部分“使用C++做设计”，这样的内容在类似的程序设计语言书籍中很难看到 — 我甚至认为Bjarne应该将这部分独立出来单独写一本书。 <br /><br />Bjarne Stroustrup, The Design and Evolution of C++ <br />《C++语言的设计和演化》，机械工业出版社 <br />《C++语言的设计和演化（英文版）》，机械工业出版社 <br /><br />D&amp;E是一本关于C++语言设计原理、设计决策和设计哲学的专著。它清晰地回答了C++为什么会成为今天这个样子而没有变成另外一种语言。作为C++语言的创建者，Bjarne淋漓尽致地展示了他独到而深刻的见解。除了广受赞誉的语言特性外，Bjarne没有回避那些引起争议的甚至被拒绝的C++特性，他一一给出了逻辑严密、令人信服的解释。内容涵盖C++的史前时代、带类的C、C++的设计规则、标准化、库、内存管理、多重继承、模板等，对包括异常机制、运行时类型信息和名字空间在内的重要的新特性都分别进行了深入探讨。每一名C++程序员都应该可以从Bjarne的阐释中加深对手中这门语言的认识。 <br /><br />需要再次提醒的是，这两本书知识浓缩，信息量极大，请不要错过Bjarne每一句看似漫不经意的话。 <br /><br />入门教程 <br /><br />学习任何一门语言都需要一个从入门到精通、从新手到高手循序渐进的过程。不过，对于一个所谓的新手而言，究竟是一个完完全全的新手，还是一个熟悉某种别的语言的“新手”，甚至是在某种语言程序设计领域已经颇有建树的高手，很难一概而论？不同的C++新手需要不同的入门书籍。 <br /><br />Andrew Koenig, Barbara E. Moo, Accelerated C++: Practical Programming by Example <br />《Accelerated C++中文版》，中国电力出版社 <br /><br />和市面上大多数C++教程不同，本书不是从“C++中的C”开始讲解，而是始于地道的C++特性。从一开始就使用标准库来写程序，随着讲述的逐渐深入，又一一解释这些标准库组件所依赖的基础概念。另外，和其他C++教材不同的是，这本书以实例拉动语言和标准库的讲解，对后两者的讲解是为了给实例程序提供支持，而不是像绝大多数C++教材那样，例子只是用作演示语言特性和标准库用法的辅助工具。 <br /><br />作者在C++领域的编程实践、教育培训以及技术写作方面都是世界一流水准。我喜欢这种大量使用标准库和C++语言原生特性的清新的写作风格。在这本教材面前，几乎迄今为止的所有C++教材都黯然失色或显得过时。尽管这本教材也许对于国内的高校教育来说有些前卫，不过我仍然极力向我的同行们推荐。顺带一提，在Bjarne和我最近的一封通信里，他这样评价本书：对于有经验的程序员学习C++而言，这本书可能是世界上最好的一本。 <br /><br />Stanley B.Lippman, Josee Lajoie, C++ Primer (3rd Edition) <br />《C++ Primer (3RD)中文版》，中国电力出版社 <br /><br />这本书的名字多少有点让人误解。尽管作者声称这本书是为C++新手而写，但无论是它的厚度还是讲解的深度都暴露了似乎并非如此。也许说它是一本“从入门到精通”的C++教程会更合适一些。我个人认为它并不适合完全不懂C++的初学者 — 在阅读这本书之前，你至少应该先有那么一点C或C++的背景知识，或者至少要具有一些其他语言的编程经验。 <br /><br />尽管这本书省略了一些高级C++特性的讨论，但仍然可以称得上是迄今为止最全面的C++学习教程。事实上，如果一名C++初学者能够扎扎实实地读完本书并对照《C++ Primer Answer Book》完成全部习题的话，他的水平肯定可以进入职业C++程序员的行列。我个人认为，即使你已经拥有了TCPL，这本书依然有拥有的价值，因为在许多方面它比TCPL来得更详细、更易懂。 <br /><br />Stanley B. Lippman, Essential C++ <br />《Essential C++中文版》，华中科技大学出版社 <br />《Essential C++（影印版）》，中国电力出版社 <br /><br />可以不太严格地认为这本书是《C++ Primer》的精简版。本书一一讲述了C++中最具代表性的主题，包括过程式编程、泛型编程、基于对象编程、面向对象编程、模板编程以及异常处理等。Stanley将门槛调低到“具有其他语言程序设计经验”的C++新手所能接受的最基本的层次，使他们能够迅速开始使用C++编程而又免于阅读《C++ Primer》那样的大部头。它以实例引导学习，力图使读者在最短的时间内把握C++的精粹。 <br /><br />也许换一个人来概述C++编程范型（paradigm）的方方面面需要好几百页才能说清楚，但这本小书不可思议地做到了这一点。我个人非常喜欢这种满是技术、简明扼要并且“有话好好说”的书。这本书同样具有一个明显的风格：所有程序例子全部采用标准库组件，让人耳目一新。 <br /><br />以上三本书都不是为了完完全全的编程新手而写。完全的C++编程新手可以阅读Francis Glassborow的新书（尚未出版）：《A Beginners Introduction to Computer Programming : You Can Do It!》。这也是Bjarne的推荐。Francis Glassborow是ACCU主席，多年来他对几乎每一本C++经典名著评头论足，他自己的这一本自然会引起C++社群的极大兴趣。 <br /><br />高效、健壮编程 <br /><br />两年前我在负责一个省级电力调度系统项目时编写了一个网关程序，它从SCADA系统获取电力实时信息。通讯接口采用了不常用的数据库直连方式（这个网关程序一端连接SQL Server 6.5，另一端连接Oralce 8.1.6）。由于实时测点近万，每次将全部取样更新或插入一遍显然是低效的。我在网关程序里建了一个内存库，获取到的数据首先在其中进行比较，然后决定是否更新物理数据库（同时还做了别的更复杂的事情……），从而在效率和资源占用两方面达到了预期效果。 <br /><br />这个程序一直运行得很好，但在离开现场之后的某一天，系统管理员打来电话，说大概因为网络故障等原因，有时这个网关程序会崩溃掉 — 它自己崩掉也就罢了，问题是它还会把Windows 2000 Advanced Server搞成“蓝屏”！坦白地说，我还从来没看过哪个非蓄意的程序有这个“能耐”。由于当时正忙于另外一个大项目，无法去现场调试，最后只有凭经验对内存库代码小心翼翼地封装以异常处理代码（同时也做了一些别的修改……）。这样，虽然没有彻底解决问题，但程序终究不再死得那么难看了。 <br /><br />在这儿讲这么一段花絮有什么意思呢（当初为那个可怕的bug朝思暮想时我可不认为这是一个“花絮”）？我想说的是，对于任何软件而言，离开强健，效率也就无从谈起。而对于C++程序员来说，也许编写一个高效的程序并不难，但要编写一个需要7 ⅹ 24小时持续运行的服务端软件就不是那么容易了，需要考虑许多因素，有时这些因素甚至远远超出C++语言和开发工具的本身。作为一名开发实际项目软件的程序员，并非非得自己碰钉子才能积累经验，只要我们足够虚心，别人的经验往往都是我们很好的借鉴。鉴于此，我推荐以下几本书供你选读，它们可以让你从强健和效率两方面受益（当然了，它们涵盖的内容远不限于异常处理J）。 <br /><br />Scott Meyers, Effective C++: 50 Specific Ways to Improve Your Programs and Design (2nd Edition) <br />Scott Meyers, More Effective C++: 35 New Ways to Improve Your Programs and Designs <br />《Effective C++中文版》，华中科技大学出版社 <br />《More Effective C++中文版》，中国电力出版社 <br />《Effective C++（影印版）》，中国电力出版社 <br /><br />如果说《Effective C++》主要讨论C++中一些相对基础的概念和技巧的话，那么《More Effective C++》则着重探讨了包括异常处理在内的一系列高级技术。与前者相比，后者具有两大主要区别：其一，它包含很多时新的标准C++的内容；第二，它讨论的主题倾向于“战略化”而非“战术化”，并且讨论得更深入、更彻底。尤其是对虚析构函数、智能指针、引用计数以及代理类（proxy classe）等技术和模式论述的深入程度，让人很难想象是出现于这样的一本小书之中。 <br /><br />游刃有余的技术，高超的写作技巧，Scott无疑是世界上最优秀的C++技术作家之一。在简洁、清晰、易读等方面，这两本书都卓尔不群。总之，Scott提供的这85个可以改善编程技术和设计思维的方法，都是中、高级C++程序员必备的技能。我强烈推荐这两本书（实际上还有一本，稍后就会看到）。 <br /><br />Herb Sutter, Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions <br />Herb Sutter, More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions <br />《Exceptional C++中文版》，中国电力出版社 <br />《More Exceptional C++中文版》，华中科技大学出版社 <br /><br />你自认为是一名C++语言专家吗？读一读ISO C++标准委员会秘书长的这两本书再回答。在这两本书中，Herb采用了“问答”的方式指导你学习C++语言特性。对于每一个专题，Herb首先合理地设想出你的疑问和困惑，接着又猜测出你十有八九是错误的解答，然后给你以指点并提出最佳解决方案，最后还归纳出解决类似问题的普适性原则。 <br /><br />这两本书是典型的深究C++语言细节的著作，很薄，但内容密集，远远超过Scott的那两本书，读起来很费脑筋 — 我个人认为它们要比Scott的书难懂得多。若要研习这薄薄的两本书所包含的知识，至少需要花费数月的时间！（在Scott的荐序中，他坦陈不止一次陷入GotW问题的陷阱，你应该知道这意味着什么）对于语言细节的深究有什么好处呢？尽管在大多数情况下，我们不必关心C++代码幕后的动作，然而当我们不得不关心时，这两本书可以为我们提供很好的线索，因为它们揭示了C++语言中微妙而又至关重要的东西。 <br /><br />Stephen C. Dewhurst, C++ Gotchas: Avoiding Common Problems in Coding and Design <br />《C++程序设计陷阱》，中国青年出版社 <br /><br />Stephen的理论素养和实践经验注定这是一本值得一读的好书。Stephen曾经是贝尔实验室中第一批C++使用者。他已经使用C++成功解决了包括编译器、证券交易、电子商务以及嵌入式系统等领域中的问题。本书汇集了作者来自开发一线的99条编程真知灼见，洞悉它们，你可以避免几乎所有常见的C++设计和编程问题。 <br /><br />我甚至认为，对于C++编程菜鸟而言，阅读这本书会比阅读Scott和Herb的书更能轻松而立竿见影地获得更大的提高。我个人很喜欢这本书的写作风格 — Stephen的许多观点看似极端却无可辩驳。当然了，这种自信（以及冷幽默）来自于作者深厚的技术素养，而非自大的偏执。 <br /><br />除了上面推荐的书籍外，Dov Bulka和 David Mayhew合著的《Efficient C++: Performance Programming Techniques》（《提高C++性能的编程技术》，清华大学出版社）也值得一看。这本超薄小书聚焦于高性能C++应用程序开发。两位作者都是IBM软件专家，都工作于对性能要求极高的系统构建领域，本书是他们的经验之谈。也有人不喜欢这本书，因为它花了不少的篇幅讲述和C++无关的东西，我却恰恰因为这一点而对这本书产生好感，正是这些东西让我开阔了眼界。 <br /><br />模板和泛型编程 <br /><br />模板和基于模板的泛型编程无疑是当今发展最活跃的C++程序设计技术。模板的第一个革命性的应用是STL，它将模板技术在泛型容器和算法领域的运用展现得淋漓尽致，而Boost、Loki等现代程序库则将模板技术的潜能不断发挥到极致。在模板和泛型编程领域，我推荐以下两本重量级著作： <br /><br />David Vandevoorde, Nicolai M. Josuttis, C++ Templates: The Complete Guide <br />《C++ Templates全览（繁体版）》，台湾碁峰资讯股份有限公司 <br />《C++ Templates全览（简体版）》，人民邮电出版社 <br /><br />有一种老套的赞美一本书的手法，大致是“没有看过这本书，你就怎么怎么地”，这里面往往夸张的成分居多。不过，倘若说“没有看过《C++ Templates: The Complete Guide》，你就不可能精通C++模板编程”，那么这个论断对于世界上绝大多数C++程序员来说是成立的。 <br /><br />这本书填补了C++模板书籍领域由来已久的空白。此前，上有《Modern C++ Design》这样的专注于模板高级编程技术和泛型模式的著作，下有《The C++ Standard Library》这样的针对特定模板框架和组件的使用指南。然而，假如对模板机制缺乏深入的理解，你就很难“上下”自如。鉴于此，我向每一位渴望透彻理解C++模板技术的朋友推荐这本书。 <br /><br />这本书在内地、台湾各有一个译本，但出自不同的译者之手。当你看到这篇文章时，两个译本应该都已经上市，对于读者来说当然也就多了一种选择。侯捷先生个人网站上开放了繁体译本大部分章节，不妨先睹为快。 <br /><br />Andrei Alexandrescu, Modern C++ Design: Generic Programming and Design Patterns Applied <br />《C++设计新思维：泛型编程与设计模式之应用》，华中科技大学出版社 <br />《C++设计新思维（影印版）》，中国电力出版社 <br /><br />你自认为是C++模板编程高手吗？请看过这本书再回答J 这是一本出自天才之手令人敬畏的杰作。泛型模式，无限延伸你的视野，足以挑战任何一名C++程序员的思维极限。 <br /><br />这本书共分为两大部分，第一部分讨论了 Loki程序库采用的基础技术以及一些高级语言特性，包括基于策略的类设计、模板局部特化、编译期断言、Typelist以及小型对象分配技术等。第二部分则着重介绍了Loki中的重要组件和泛型模式技术，包括泛化仿函数（Generalization Functor）、单件（Singleton）、智能指针、对象工厂（Object Factory）、抽象工厂（Abstract Factory）、访问者（Visitor）以及多方法（Multimethods）等。每一种技术都让人大开眼界，叹为观止。 <br /><br />在C++的学习方面，过犹不及往往成了不求甚解的借口。然而，面向对象并非C++的全部，模板和泛型编程亦占半壁江山。对于“严肃”的C++程序员而言，及时跟进这项早经例证的成功技术，不失为明智之举。 <br /><br />结语 <br /><br />这些著作是如此大名鼎鼎，也许根本不缺我一个推荐。然而，纵然C++程序员队伍的发展壮大速度不像其他更时髦的语言那样迅速，新人进总是多于旧人出。除了热忱地欢迎新人，我个人认为到了对C++书籍进行“盘点”的时候了，并且希望这样的“盘点”有益于感兴趣的读者。请保持耐心和宽厚。在下篇中，我将继续介绍标准库、网络编程以及其他方面的C++好书。有好书相伴，这个冬天不会冷。<img src ="http://www.cppblog.com/threesh/aggbug/13899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/threesh/" target="_blank">Cpp Fans</a> 2006-10-20 14:53 <a href="http://www.cppblog.com/threesh/archive/2006/10/20/13899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>