01 / 导读
导读
引用
Kernighan, B. W., & Ritchie, D. M. (1988). The C Programming Language (2nd ed.). Prentice Hall.
章节概要
第二版篇幅紧凑(出版社列出的页数为288页,索引从第263页开始),包括序言、导言、八章和三个附录。本书由 C 语言的设计者 Ritchie 和他在贝尔实验室的同事合著,按照 ANSI 标准描述 C 语言——本书付印时该标准正在定稿;最早的印次封面上印有“Based on Draft-Proposed ANSI C”,之后的印次则印有红色的“ANSI C”字样。序言说明了作者的目标:保持第一版(1978年)的简洁,因为 C 不是一门大语言,也不适合用一本大书来讲;改进对指针等核心特性的讲解;主要通过阅读、编写和修改完整且经过测试的程序来教学,而不是罗列规则。各章都有编号的练习。
第1章:A Tutorial Introduction(入门教程)
快速浏览语言的核心部分,目的是让读者尽快开始写程序:入门、变量与算术表达式、for 语句、符号常量、字符输入与输出、数组、函数、传值调用、字符数组,以及外部变量与作用域。导言明确指出,这一教程假定读者具备编程的实际知识,不解释计算机、编译或赋值语句的含义。
第2章:Types, Operators, and Expressions(类型、运算符与表达式)
更正式的讲解从这里开始:变量名、数据类型与长度、常量、声明、算术运算符、关系与逻辑运算符、类型转换、自增与自减运算符、按位运算符、赋值运算符、条件表达式,以及优先级与求值次序。
第3章:Control Flow(控制流)
语句与程序块、if-else 和 else-if 结构、switch、while 和 for 循环、do-while、break 和 continue,以及 goto 与标号。出版社公开的本章样章体现了全书的风格:简短而完整的函数(二分查找、数字与字符串之间的转换),后面是要求读者改写或扩展这些函数的练习。
第4章:Functions and Program Structure(函数与程序结构)
函数以及如何围绕函数组织程序:返回非整数值的函数、外部变量、作用域规则、头文件、静态变量和寄存器变量、程序块结构、初始化、递归,以及 C 预处理器。据导言介绍,本章也讨论分布在多个源文件中的程序。
第5章:Pointers and Arrays(指针与数组)
这是讲解语言的各章中最长的一章,也是序言特别提到改进了讲解的一章。内容包括指针与地址、作为函数参数的指针、指针与数组的关系、地址运算、字符指针、指针数组与指向指针的指针、多维数组、命令行参数、指向函数的指针,以及复杂声明;据序言介绍,最后这部分用把声明转换为文字、再把文字转换回声明的程序来说明。
第6章:Structures(结构)
结构及其与函数的配合、结构数组、指向结构的指针、自引用结构(链式数据结构的基础)、一个表查找的例子、typedef、联合以及位字段。
第7章:Input and Output(输入与输出)
把标准库作为通向操作系统的可移植接口:标准输入与输出、用 printf 进行格式化输出、变长参数表、用 scanf 进行格式化输入、文件访问、用 stderr 和 exit 处理错误、行输入与输出,以及其他函数。
第8章:The UNIX System Interface(UNIX 系统接口)
C 程序如何直接使用 UNIX 系统调用:文件描述符、低级的 read 和 write、open、creat、close 和 unlink,以及用 lseek 随机访问。随后是三个较完整的例子:fopen 和 getc 的实现、一个列出目录的程序,以及一个存储分配器。导言指出,虽然本章部分内容是 UNIX 特有的,但它也展示了标准库的一种实现可以如何完成。
附录A–C:Reference Manual(参考手册);Standard Library(标准库);Summary of Changes(变更摘要)
附录A是一份参考手册,面向程序员而非编译器编写者,以较小的篇幅传达 ANSI 标准的要点,最后附有文法。附录B按头文件逐一概述标准库,从 stdio.h 到 limits.h 和 float.h。附录C列出了相对于第一版原始语言的变化。
核心概念
第1–3章:语言核心
- 函数原型:列出参数类型的 ANSI 声明形式,导言称之为对大多数程序员来说最重要的变化。
- 类型转换:在表达式中组合不同类型的值时遵循的规则。
- 按位运算符:作用于整数各个二进制位的运算符。
- 结构化控制流:if-else、switch、while、for、do-while、break 和 continue。
第4–6章:程序结构、指针与结构
- 作用域与外部变量:程序的哪些部分能看到某个名字,包括跨源文件共享的变量。
- 预处理器:在正式编译之前进行的宏替换、文件包含和条件编译。
- 指针运算:在数组内部计算地址,以及指针与数组之间的密切关系。
- 自引用结构:包含指向同类型结构的指针的结构,用来构建链表和树。
第7–8章:库与系统
- 标准库:由 ANSI 定义的函数和头文件集合,使输入、输出及其他系统访问具有可移植性。
- 系统调用:由操作系统提供的 read、write、lseek 等低级操作。
- 存储分配:显式管理内存,以一个存储分配器为例说明。
评析
优点
- 简洁而精确。 作者有意让本书保持短小,因为这门语言本身就小;整门语言、标准库概要和参考手册加起来不到300页。出版社引用了 Bjarne Stroustrup 的评价,他称赞教程各章看似轻松简单的风格和参考手册的干净利落。
- 从完整的程序中学习。 序言强调书中是直接从正文测试过的完整、真实的程序,练习则要求读者修改这些程序;作者还力求展示有用的算法以及良好风格和合理设计的原则。示例程序可以从出版社下载,每章一个目录。
- 出自语言设计者之手。 参考手册和对标准的讲解出自定义 C 语言的人,而导言对语言的缺点也很坦率,承认有些运算符的优先级不对、部分语法还可以更好。
- 通向系统编程的桥梁。 第8章展示了库如何建立在系统调用之上,并以一个存储分配器收尾,把语言与操作系统和库的工作原理联系起来。
局限
- 不是第一本编程书。 序言直言本书不是编程入门手册,假定读者熟悉变量、赋值、循环和函数;新手也能跟着读,但最好有经验更丰富的人帮助。
- 描述的是1988年的 ANSI C。 本书按1988年 ANSI 标准的定义来描述 C。此后 C 标准的修订没有涉及,读者需要从别处学习新特性和当前的库用法。
- 讲语言,不讲数据结构。 导言说明本书不是数据结构与算法的参考书;在必须取舍时,作者把重点放在语言上。
- 勘误与印次。 Ritchie 维护了一份已出版版本的已知错误清单,其中许多已在后来的印次中更正;使用旧书的读者应当参考它。
在课程中的定位
本入门编程课程中的其他书大多是为从未编过程的人写的。Matthes 的 Python Crash Course 先用短小的练习教授 Python 的核心,再进入三个项目;Felleisen 等人的 How to Design Programs 用随学生一起成长的教学语言讲授系统的设计方法;Downey 的 Think Python 和 Guttag 的 Introduction to Computation and Programming Using Python 通过 Python 介绍计算机科学。Kernighan 和 Ritchie 以这样的第一门课为前提,把读者带到更低的层次:内存、地址、指针,以及高级语言所隐藏的操作系统接口。
Abelson 和 Sussman 的 Structure and Interpretation of Computer Programs 则走向相反的方向:抽象、高阶过程和解释器。两本都读,可以看到编程的两端:从一门小语言向上构建抽象,以及直接管理机器。读完一本 Python 书的学生,接下来读本书正合适,也可以与计算机组成或操作系统课程同时阅读。
如何使用本书
本书适合已经会用某种语言编程、想认真学习 C 的学生,尤其是将要学习系统编程、嵌入式开发或操作系统课程的学生。
- 在键盘前读第1章。 输入并运行每一个例子;作者认为,学习一门语言的方法就是用它写程序。
- 核心: 按顺序读第2–6章。在第5章上花最多的时间;在进入第6章之前,用小的测试程序和内存示意图把指针与数组弄明白。
- 库与系统: 写实用程序离不开第7章。第8章初读时可以跳过,但对修读系统类课程的学生收获很大;存储分配器值得逐行研读。
- 参考: 附录A和B用于查阅,而不必通读。
一定要做练习:练习简短,与例子紧密相连,许多是对正文程序的扩展。用现代编译器并打开警告进行编译,利用出版社提供下载的示例程序和 Ritchie 的勘误表核对正文。关于后来的 C 标准,应以最新的参考资料作补充。
