第2版前言
在计算领域中,把显而易见的转变为有实用价值的,这一过程是“挫折”一词的生动体现。
自本书第1版出版以来,基于C的语言大量兴起(其中最杰出的是Java和C#),C++和Perl等相关语言也取得了更大的成就。尽管如此,C语言仍然像当年一样流行,悄无声息地掌控着世界上的许多软件。跟1996年一样,C语言仍然是计算机领域里的通用语言。
然而,即便是C语言也必须随着时间而发展。C99标准的发布催生了对本书第2版的需求,而且,第1版涉及的DOS和16位处理器也趋于过时。同样,C11和C18的发布促使修订版对内容进行了全面更新,并在其他许多方面做了改进。
修订版新增内容
下面列出了这一版的新特色和所做的改进。
-
完整覆盖了C89、C99和C1
X
标准
。这一版和第1版的最大差别就在于覆盖了C99和C1
X
标准。我的目标是覆盖C89、C99和C1
X
之间的每一个重要差别,包括新标准新增的所有语言特性和库函数。新标准中的每一处改变都会清楚地用C99或者C1
X
标出来,或者在节标题上,或者进行简短讨论时在正文左边空白处。这样做有两个目的:一是提醒读者注意新标准中的改变,二是让那些对新标准不感兴趣或没有新标准编译器的读者知道哪些内容可以跳过。新标准新增的许多内容可能只有特定的读者会感兴趣,但有些新特性几乎对所有的C程序员都有用。这一版中有关C1
X
的内容(包括整个第28章)是由李忠负责完成的,他修正了原书中过时的内容和不准确的表述,调整了部分术语的中文译法,并更正了上一版中的翻译问题。
-
提供了对所有C89、C99和C1
X
库函数的快速参考
。第1版附录E介绍了C89的所有标准库函数,这一版附录E给出了C89、C99和C1
X
的所有库函数。
-
扩展了GCC的内容
。自本书第1版出版以来,GCC(最初是GNU C Compiler的简称,现在指GNU Compiler Collection)得到了广泛应用。GCC有很多优点,包括高性能、低成本(不用花钱)以及在众多软硬件平台之间的可移植性等。由于认识到GCC日渐重要,我在这一版中介绍了更多与GCC相关的信息,包括如何使用GCC以及常见的GCC出错消息和警告。截至目前,GCC尚未在它的C标准库实现中添加多线程支持,在学习本书第28章时,建议使用Pelles C。尽管不那么有名,但它是当前对标准支持最好的C语言开发工具。
-
增加了对抽象数据类型的讨论
。在第1版中,第19章重点讨论了C++。这部分内容现在看起来似乎作用不大,因为本书的读者可能已经学过C++、Java或者C#了。在这一版中,我将对C++的介绍替换为讨论如何在C中建立抽象数据类型。
-
扩展了国际化特性的内容
。这一版第25章更加详尽地讨论了C语言的国际化特性,重点扩展了Unicode字符集及编码。
-
针对CPU和操作系统做了更新
。当我编写本书第1版时,许多读者用的还是16位机和DOS操作系统,但现在情况不同了。在这一版中,我把讨论的重点放在32位机和64位机上。鉴于Linux和其他版本UNIX的兴起,我们会对该类操作系统给予更多关注。不过,在可能影响到C程序员的场合,我们也会提到Windows和macOS操作系统的相关方面。
-
引入了多线程的内容
。从C11开始,新标准的最大变化是引入了多线程和原子操作。这部分内容较多,而且是非常新颖的内容,值得大书特书,并作为一个整体系统性地加以介绍,为此我们把它放在第28章。市面上和C语言有关的图书多如牛毛,但据我们所知,介绍多线程和原子操作的图书,这还是第一本。
-
更多的练习题和编程题
。本书第1版包括311道习题,这一版有500多(准确地说是502)道习题,分为两组:练习题与编程题。
-
练习题和编程题的答案
。本书第1版的读者反馈最多的问题就是希望我提供习题的答案。针对读者的这一需求,我将大约三分之一的练习题和编程题的答案放到了网上,见
https://exl.ptpress.cn:8442/ex/l/609033ea
。这一特色对于那些没有选修相应大学课程却需要检验自己工作的读者来说是非常有用的。提供了答案的练习题和编程题
都用
图标做了标记。
-
有密码保护的教师网站
。我为这一版建了一个新的教师资源网站(通过
https://exl.ptpress.cn:8442/ex/l/609033ea
访问),给出了其余练习题和编程题的答案以及大部分章节的PowerPoint讲义。教师可以通过
cbook@knking.com
与我联系。请使用贵校的邮箱地址并给出贵系网站的链接,以便我核实您的身份。
此外,我在这一版中对全书的文字和解释说明做了改进。这些改变所需的工作量很大,过程很辛苦:每句话都检查过并(在必要的时候)重新写过。
尽管这一版改动很大,我仍然尽可能多地保持了原有的章节编号。尽管第27章和第28章的内容是全新的,但其他许多章都有新增的内容,少数原有章节的顺序也有所变动。这一版删去了一个附录(C语言语法),但新增了C1
X
、C99和C89的附录。
目标
这一版的目标与第1版一致。
-
清晰易读,并尽可能带有趣味性
。对普通读者来说,许多C语言的书过于简洁,而某些甚至不是编写得一塌糊涂,就是平淡无趣。我试图对C语言进行清晰、全面的讲解,并用适当的幽默来激发读者的阅读兴趣。
-
适用于广泛的读者
。我假设本书的读者都至少有一点点编程经验,但不需要掌握某种具体的编程语言。我尽量减少“行话”并定义用到的每一个术语。同时,为了鼓励初学者,我还会尝试将某些高级内容从基本主题中分离出来。
-
有权威性,但不是学究气十足
。为了避免武断地决定应该包含哪些内容、不应该包含哪些内容,我尽量涵盖了所有C语言的特性和库函数。同时,为了避免给读者造成负担,我还省略了一些不必要的细节。
-
具备简单易学的组织结构
。根据多年教授C语言的经验,我强调循序渐进地展示C语言特性的重要性。针对有一定难度的主题,我采用了螺旋式的介绍方法。也就是说,对于较难的主题先进行简要介绍,然后在后续章节中再进行一次或多次介绍,每次逐渐增加一些细节内容。本书的进度是经过深思熟虑的。每章都按照循序渐进的方式进行组织,前后内容由浅入深,相互呼应。对于大多数学生来说,这种循序渐进的方法是最合适的:既能避免产生厌倦,又能防止“信息过载”。
-
深入探讨语言特性
。我的目标不是仅描述语言的每个特性,并展示应用该特性的几个简单示例,而是尝试深入讲解每一个特性,并且探讨如何将其应用到实际问题中。
-
强调编码风格
。对每位C程序员来说,采用统一的编码风格是非常重要的。但是,与指定某种风格相比,我更愿意给出多种编码风格,让读者根据自己的喜好做出选择,因为了解多种编码风格对阅读别人的程序是很有帮助的(程序员经常要花费大量时间阅读别人的程序)。
-
避免依赖任何特定的计算机、编译器或操作系统
。C语言可以应用在许多平台上,所以我尽量避免使编写的程序依赖于任何特定的计算机、编译器或操作系统。所有程序都经过精心设计,可以移植到多种平台上去。
-
用图示来阐明关键概念
。我在书中加入了尽可能多的图,因为我认为图对于理解C语言的许多方面都至关重要。特别地,我尽可能地通过图来显示不同计算阶段的数据状态,以此来动态地展示算法。
现代方法到底指的是什么
本书最重要的目标之一就是通过一种“现代方法”来介绍C语言。我试图通过以下这些途径来实现这一目标。
-
正确看待C语言
。我没有把C语言看作唯一值得学习的编程语言,而是把它作为众多实用语言中的一种来介绍。我在书中提到了最适合用C语言编程的应用类型。此外,我还展示了如何扬长避短地使用C语言。
-
强调C语言的标准版本
。我尽可能少地关注C89标准之前的C语言,只是零星地提到了经典(
K&R
)C语言(Brian W. Kernighan和Dennis M. Ritchie所著的《C程序设计语言》第1版中所描述的1978版C语言)。附录D列出了C89和经典C之间的主要差异。
-
揭穿神话
。现今的编译器常常与过去的C语言基本假设不一致,我很乐于揭穿C语言的某些神话,并挑战一些存在了很久的C语言信条(例如,指针的算术运算一定比数组下标操作快)。我重新审查了C语言的旧惯例,保留了那些仍然有帮助的惯例。
-
强调软件工程
。我把C语言视为一种成熟的软件工程工具,着眼于如何运用C语言来处理大规模程序设计过程中产生的问题。本书强调程序要易读、可维护、可靠且容易移植,尤其重视信息隐藏。
-
推迟介绍C语言的底层特性
。虽然这些特性对于那些用C语言编写的系统来说非常有用,但现在它们已经不那么适用了,因为C语言的应用比以前广泛得多。本书没有像诸多其他C语言书那样把这部分内容放在前面介绍,而是推迟到第20章再讲述。
-
不再强调“手工优化”
。许多书会指导读者编写一些技巧性较强的代码,以获得程序效率的些许提高。如今优化的C语言编译器随处可见,这些编程技巧往往已经不必要了;事实上,它们反而会降低程序的运行效率。
“问与答”部分
每章的末尾都有一个“问与答”部分,汇集了与本章内容相关的问题及其答案。“问与答”部分包括以下内容。
-
常见问题
。我尽力回答了某些频繁出现在我的课堂里、其他图书中及与C语言相关的新闻组里的问题。
-
对一些难以理解的问题的进一步讨论和澄清
。虽然具有多种编程语言经验的读者会满足于简明扼要的说明和少量的示例,但是缺乏经验的读者需要更多的内容以帮助理解。
-
非主流的问题
。某些问题所引出的技术问题并不是所有读者都感兴趣的。
-
某些对普通读者来说过于超前或深奥的内容
。这类问题都用星号(*)做了标记。好学且有一定编程经验的读者也许希望立刻深入研究这些问题,而另外一些读者则需要在首次阅读时跳过这部分内容。
提示
:这类问题往往引用后续章节的内容。
-
C语言编译器之间的常见差异
。我讨论了某些特定编译器所提供的一些频繁使用的(非标准)特性。
“问与答”部分中的某些问题与对应章中的具体内容直接相关,我用一个专门的图标
来标记这些具体内容,以提示读者有附加信息可用。
其他特色
除了“问与答”部分,我还加入了许多有用的特色,其中很多都用简单而独特的图标做了标记。
-
警告
(
)警示读者一些常见的缺陷。C语言以其陷阱多而出名,要记录所有的陷阱非常困难。我试着挑选出了一些最常见或最重要的缺陷供大家参考。
-
交叉引用
(➤)提供一种类似超文本的能力来定位信息。多数引用指向后续章节中的内容,也有一些引用指向先前的内容供读者回顾。
-
惯用法
是C语言程序中常见的代码模式。它被标记出来以便于速查参考。
-
可移植性技巧
给出了编写不依赖于特定计算机、编译器或操作系统的程序所需的提示。
-
附加说明
包含一些严格来讲并不属于C语言的内容,但每位熟练的C程序员都应该知道。(下面的“源代码”给出了附加说明的示例。)
-
附录
提供有价值的参考资料信息。
程序
选择程序示例并不是件轻松的工作。如果程序过于简洁和做作,那么读者将无法体会如何将这些特性应用于现实世界。如果程序过于真实,那么它的要点将很容易被埋没在过多的细节中。我采取了折中方案。在首次介绍时,先通过小而简单的示例使概念清晰,然后再逐步建立完整的程序。我没有使用过长的程序,因为根据我个人的经验,教师没有时间介绍这些内容,学生也不会有耐心去阅读。但是,我并没有忽视编写大规模程序时会出现的问题,相关内容在第15章和第19章中进行了详细的介绍。
这一版的程序有些小变化。在大多数情况下,
main
函数的格式为
int main (void){...}
。这一改变既反映了业界的惯例,又能够与C99兼容:C99要求每个函数都有一个显式的返回类型。
读者
本书是为大学本科阶段的C语言课程编写的教材。具有其他高级语言或汇编语言的编程经验会对阅读本书很有帮助,不过这些经验对于会用计算机的读者(我以前的一位编辑称他们为“熟练的初学者”)来说并不是必需的。
因为本书内容齐备、自成一体,并且既可用于学习又可作为参考,所以它非常适合作为其他一些课程的辅助读物,如数据结构、编译器设计、操作系统、计算机图形学、嵌入式系统及其他要用C语言进行项目设计的课程。“问与答”部分以及对实际问题的强调,使得本书对于培训班学员和自学C语言的人来说也很有吸引力。
组织结构
本书分为4个部分。
-
C语言的基本特性
。第1~10章包含的C语言内容足以帮助读者编写出使用数组和函数的单文件程序。
-
C语言的高级特性
。第11~20章建立在前面各章内容的基础上,内容有一定的难度,深入介绍了指针、字符串、预处理器、结构、联合、枚举以及C语言的底层特性。此外,第15章和第19章提供了程序设计方面的指导。
-
C语言标准库
。第21~28章集中介绍C语言库——与编译器相关联的庞大函数集合。其中一部分内容适合课堂讲解,但大部分材料更适合作为参考。
-
参考资料
。附录A给出了C语言运算符的完整列表。附录B描述了C1
X
和C99之间的主要差别。附录C描述了C99和C89之间的主要差别。附录D讨论了C89和经典C之间的差异。附录E按字母顺序列出了C89、C99以及C1
X
标准库中的全部函数,并为每个函数给出了详尽的说明。附录F列出了ASCII字符集。还有一个带注解的延伸阅读列表为读者指明了其他的信息来源。
全面讲授C语言的课程应该按顺序覆盖前20章的内容,并根据需要增加第21~28章中的一些内容(其中讨论了文件输入/输出的第22章最为重要)。短期课程可以忽略以下内容而不失连贯性:8.3节(C99中的变长数组)、9.6节(递归)、12.4节(指针和多维数组)、14.5节(其他指令)、17.7节(指向函数的指针)、17.8节(受限指针)、17.9节(弹性数组成员)、18.6节(内联函数)、第19章(程序设计)、20.2节(结构中的位域)和20.3节(其他底层技术)。
练习题和编程题
作为一本教材,拥有多样化的精选习题显然是非常必要的。这一版既有练习题(不需要写出完整程序的简短习题)又有编程题(需要编写或修改完整程序的习题)。
有些练习题的答案不是显而易见的(有人称其为“刁钻问题”)。因为C语言程序经常包含这类代码的大量案例,所以我认为有必要提供一些这样的练习,并用星号(*)做了标注。一定要谨慎地对待有星号的习题:要么格外小心,认真考虑;要么干脆绕开它。
反馈
为了保证本书内容准确,我付出了极大的努力。然而,任何这种篇幅的书都不可避免地会有一些错误。如果读者发现了错误,请通过
cbook@knking.com
这个电子邮箱与我联系。我也同样期望听到读者的其他反馈,比如,你觉得哪些内容特别有用,哪些内容没什么用,希望添加哪些内容等。
致谢
首先,我要感谢本书的编辑——Norton出版社的Fred McFarland和Aaron Javsicas。本书的编辑工作最初由Fred负责,随后Aaron加入并付出了极大努力使本书得以完成。同时,还要感谢副主编Kim Yi、文字编辑Mary Kelly、生产经理Roy Tedoff和编辑助理Carly Fraser。
以下同事对这一版的部分或全部书稿进行了审阅,在此致以诚挚的谢意:Markus Bussmann(多伦多大学)、Jim Clarke(多伦多大学)、Karen Reid(多伦多大学)和Peter Seebach(comp.lang.c.moderated新闻组的主持人)。其中需要特别提到的是Jim和Peter,他们的详细审阅使这一版避免了许多错误。再次感谢第1版书稿的审稿人(按姓氏字母排序):Susan Anderson-Freed、Manuel E. Bermudez、Lisa J. Brown、Steven C. Cater、Patrick Harrison、Brian Harvey、Henry H. Leitner、Darrell Long、Arthur B. Maccabe、Carolyn Rosner和Patrick Terry。
我收到了第1版读者反馈的许多有用的意见,感谢每一位花时间提意见的读者。佐治亚州立大学的学生和同事也向我反馈了不少有价值的意见。Ed Bullwinkel和他的妻子Nancy阅读了手稿的很多内容,在此我也要感谢他们。我还要特别感谢我的系主任Yi Pan,他非常支持我的这项工作。
感谢我的妻子Susan Cole一如既往地支持着我。还有我们的猫咪Dennis、Pounce和Tex,在完成本书的过程中,它们一直陪伴着我。有时,Pounce和Tex的争吵使我在深夜写作时仍能保持清醒。
最后,我还要感谢已故的Alan J. Perlis
。他的警句出现在本书每一章的开始。20世纪70年代中期我在耶鲁大学求学期间,曾有幸在Alan的指导下进行过短暂的学习。我想如果他知道自己的警句出现在一本C语言书中,一定会非常高兴。
enTp7ogYpPeYX1aCCy0hX+/XElyTd8zifCgVghy2dsWcdYLRsa6X3dMsYTiRQiRi