前言

程序设计在计算机科学教育中的重要性是无庸置疑的。人们一直在思考第一门程序设计课应该教授什么?其教材应该是怎样的?在用C语言作为第一门程序设计课的教学语言的过程中,我编写了这个教材,是对于自己教学经验的总结。

在教学过程中学生们提出了许多问题。它们使我看到,作为这门课程所用的教材(或适合自学者的程序设计读物),需要对学习中可能遇到的问题给出合理而充分的解释,无论是关于C语言本身,还是关于程序设计过程,以使读者和学生在阅读或复习时能从中了解问题的实质,而不是自己在模糊中去设法感悟。这些对于帮助初学者尽快进入程序领域是非常重要的,也使教师在教学中有更大的自由度,更灵活地选择实例和教学方式。此外,由于程序设计的性质,基础书籍和课程中的实例不应采用“提出问题,给出解答,再加点解释”的简单三步形式,而应着重帮助初学者认识程序设计活动的实质,理解从问题到程序的思考过程。本书在这些方面做了些努力,包含了许多解释和较详细的说明。

本书编写的一个想法是要反映程序设计的两个重要特征,其科学性和工程性。科学性指程序的构造过程应有充分的科学依据:分解要解决的问题,看清各部分的意义和互相联系,这些都需要编程者对程序实现过程有科学的认识,有关研究发展形成了程序的理论。虽然初级课程或书籍里不能去深入讨论有关理论和成果,但却必须反映其精神实质,使初学者从开始就接触程序及程序语言的一些本质性问题。这一点,无论对于提高读者对计算机科学技术认识水平,还是对他们的进一步深入学习,都是非常重要的。

由于计算机的日益普及,不少人在进大学前就有了用计算机的经验,有些人已将计算机玩得很熟,甚至写过许多程序。但也应看到另一面:在学习大学课程前,学生中对程序及程序设计已建立起较正确的认识的人很少。即使是对计算机已经很熟的学生,也有许多观点需要建立,或有错误观点需要纠正。这也是本课程中应该特别强调科学性的原因。

我发现学生常有一些对计算机实质的不正确认识,有些看法可能他们也没有清楚的意识。例如有些学生在思想深处把计算机看成一种很不驯服的东西,程序设计在其头脑深处就是设计一些计谋,“骗”计算机帮人干活。有些学生把程序设计看成是玩某种计算机游戏,这里到处是陷阱和妖魔,需要在试探和失败中找一条绕过障碍的路。

日益完善的程序开发环境也可能成为学习程序设计的障碍。很好的环境造就出一类学生,他们对系统玩得很熟,键盘也打得很快。遇到程序工作时不做细致分析和设计,粗一想就动手,很快写出一大堆代码,随后进入一种三步工作循环:运行、追踪、打补丁改错。简单程序很快也就这样做出来了,但质量都很差,一个简单问题常常写出一大篇,自己也说不清解决问题的过程。即使熟悉程序的人,不花点工夫也难判断这类程序的对错,错在哪里。问题复杂时,这些同学就遇到了困难,写出的程序很难通过测试,弄不清错误出在那儿,该怎样修改。这种程序像建在沙滩上的大楼,无论如何修补都不行,最合理的建议就是推倒重来。这些情况的提示是:从简单程序开始就应该注意程序设计的正确途径。

上述情况都说明在书籍和课程中强调程序设计过程的科学性的必要。本书从开始就强调问题的分析和分解;反复讨论了函数抽象方法,讨论程序实例时也特别注意这方面问题,后面章节不断有进一步的论述。书中一些地方还通过程序实例介绍了程序理论中的一些更深入的问题,如通过对程序运行时间的测试介绍计算过程的基本性质(复杂性);通过对循环过程是否完成了所需工作的分析,介绍“循环不变关系”的概念和意义等。当然,对这些问题都没有深入讨论,只是希望读者了解有关情况,作为思考程序问题的线索。

程序设计的另一方面特征是其工程性。这里不是指规模大,参加人员多等等,而是从另一个角度看问题。在工程设计中需要对问题的分析和理解,寻找可能解决方案,对各种方案做出评价和选择。应对所做的选择有清醒的认识(它们的优点和缺点,是否对要解决问题的某些方面有所偏向或不足等),并进一步确定具体实施方案。这些问题在程序设计中都有直接反映。如果不是把学习程序设计的目的放在解决几道典型程序题目上,而是要帮助学习者提高能力、真正理解程序设计过程的话,这些问题都需要特别强调。

本书的叙述和实例都力图强调这样的观点:对于一个程序问题,并没有需要记住的标准答案。由于问题分析时的不同考虑,程序设计过程中的不同决定或选择,对同一问题,人们常会得到许多合理的“能解决问题”的程序。这些程序常是各有长短,可能有侧重点不同,也可能反映了对问题的不同认识。我们应特别注意解决问题的方法,包括如何分析问题,如何逐步把要解决的问题弄得更清楚明确,如何寻找可能的求解途径,把复杂问题分解为相对简单的步骤,如何确定可用程序语言结构并从中做出选择等。这里的每一步都可能产生分支,而在做选择时,则应该弄清选择的后果,无论是收获还是损失。

工程中往往没有十全十美的选择,更多的是权衡和折衷。这些对程序设计也是本质性的。本书对许多实例给出了较详细的分析过程,有时对一个问题给出多个解答,有时指出了其他可能性:还可能如何看问题,还可能如何做等等。还常常给读者提出一些问题,希望读者发挥自己的思维能力和主观能动性。各章节后面的练习也试图反映这些看法。

这样做的目的是希望读者能建立一种认识:程序设计是这样一种工作,这里并没有什么“标准答案”。程序设计过程中要追求的是比较好的“正确”答案,而书籍中给出的答案(包括本书)不过是作者对问题理解和分析的反映,还有很大可能的选择。进一步说,我们还希望读者养成这样的习惯:在看别人的样例程序时,应分析其中隐含了程序作者的哪些考虑和选择,哪些是合理的有价值的(或不合理的没有价值的)?哪些地方还可能有什么选择?沿着其他选择走下去可以得到什么(或失去什么)?如此等等。如果读者能养成这种思考习惯,必将从中受益无穷。当然,这并不是说书中的例子不重要。恰恰相反,正因为在程序设计过程中有许多选择的可能性,书中应当给出一些合理的好的选择,供读者参考。对于初等的入门书籍,应当同时说明为什么这样做的理由。如果可能,还应当指出采取这些选择带来的问题(缺点、造成的限制等)。

正如本书的书名所言,程序设计是“从问题到程序”的工作过程。这个工作既要求遵循严格的科学方法,又要求谨慎灵活的工程能力。要很好地完成程序设计工作,编程序的人既需要充分发挥自己的聪明才智,又需要有细致认真、一丝不苟的工作态度。即使是将来不从事计算机程序方面的工作,通过这个课程得到的锻炼也可能非常重要,尤其对于理科学生,这个课程可能对于弥补其工程方面训练的不足有所帮助。

前些年第一门程序设计课常用PASCALFORTRANBASIC等语言。目前这一课程的教学语言已转向C语言或其他类C语言(如C++等)。从作为第一门程序设计课的教学语言的角度看,没有任何程序语言具有无可比拟的天然优势,选择任何语言都应考虑其有利方面,也需要克服这样做带来的不利之处。本书是以C作为基础语言编写的教材。

选择C语言作为教学语言的主要理由有:C语言是目前实际程序设计工作中使用最广泛的语言之一,它包含了程序设计需要理解和使用的基本程序机理和主要机制。掌握这些机制就可以理解程序与程序设计的主要问题,完成程序练习,得到有关的知识积累和能力锻炼。目前有许多软件系统是用C编写的,或基本上是用C编写的。以C语言作为基本语言,不但能学习程序设计,同时也能掌握一种实用的程序设计工具。另一方面,程序设计是计算机领域的基础课程,学习C语言程序设计之后,进一步学习后续课程都比较方便。C语言适合(也正在被)作为计算机领域许多后续课程的教学语言。第三,C语言是一种很灵活的语言,用C语言写程序时常需要了解一些细节,这是人们对用C语言作为基础课语言的一个主要疑虑。但问题也有另一面,通过对C语言程序设计的较好理解,学习者可能对计算机领域的许多问题有更深的认识。这个问题实际上对课程组织、教材和教师提出了较高的要求。此外,C语言的程序既可以在较高层次上做,也可以在较低级的层次上做,学生可能从中更多了解程序设计过程中的各种问题。此外,许多后续程序语言从C语言借鉴了想法和描述方式,有些本身就是C语言的扩充和发展,C语言的知识对于进一步了解掌握许多其他语言,包括未来的新语言都是有价值的。

在撰写本书时我心中有几个努力追求的目标,列在这里供读者和同行参考:

  1. 假定读者(学生)没有程序设计经验,或只有很少经验。因此书中对在学习程序设计可能遇到的各种基本问题,各种概念和观点都应该尽量给出清楚的解释。这一考虑的目的是希望本书适合作为第一门程序设计和C语言程序设计的教材。
  2. 以讲授程序设计为基本线索,同时对C语言做深入的介绍和解释。本书希望强调如何认识程序、写程序,如何用C语言写程序。因此对从问题出发,经过分析逐步写出程序的过程有许多深入讨论。书中实例强调的是问题分析和分解,设计求解过程,找出主要步骤,确定函数抽象,找出循环,选择语言结构,最后写出程序的过程。书中不少实例给出了在不同考虑下可能形成的多种解法,以帮助读者理解程序设计的真谛。
  3. 强调好的程序设计风格,强调通过函数抽象建立起清晰的程序结构的重要性。书中很早就介绍了函数概念,从库函数使用到简单函数的书写,再到函数的确切定义。书中特别强调程序的结构性、可读性、易修改性,程序实例也努力遵循这些原则,使其简洁清楚易读。书中还根据进展和遇到的问题分析了一些不良程序设计习惯及其危害。
  4. 注意强调“好的”C程序设计及C语言描述方式。由于历史原因C语言成为一个不太严格的语言。如不注意,用C写的程序常会隐含不易发现的错误,这是把C作为第一个语言时需要解决的问题*。在ANSI C标准的基础上,存在着一套写“好的”C程序的方式。本书力图坚持ANSI C所倡导的正确程序写法,强调如何写更可靠、不易包藏隐含错误的C程序的各方面问题,并通过实例说明了应该如何写和不应该如何写等等。在坚持了上面这些原则的基础上,书中也介绍了C语言的许多实用程序设计技术。总之,本书希望强调的是如何写出正确、清晰、简洁、高效的C程序。
  5. C语言的各种结构和机制都有较细致介绍,因为其中不少问题反应了相关领域的普遍性知识和情况。本书力图对许多问题给出细致解释,不仅讲它们是怎样的,还提供了背景理由,以帮助读者理解问题实质。书中对程序设计和C语言中反映出的程序语言和程序设计的一般性问题,及计算机科学中的一般性问题也做了适度介绍和解释。

本书包括如下各章和若干附录:

第一章,程序设计与C语言。这章首先介绍了程序与程序语言的概念,C语言的发展及其特点。用一个小例子介绍了C程序的形式,C程序的加工和执行。最后介绍程序设计与开发过程,其中的各种问题,如调试、追踪、错误的排除等。

第二章,数据对象与计算。讨论程序语言的许多最基本概念,包括:字符集、标识符和关键字,数据与类型,数据表示,运算符、表达式与计算过程,数学函数库的使用等。

第三章,变量、函数和控制结构。讨论基本程序设计的一些问题,包括基本语句与复合结构,变量的概念和使用,简单函数的定义,程序中逻辑条件的描述与使用等。最后介绍了几种基本的控制结构。

第四章,基本程序设计技术。本章首先分析了循环程序设计的基本问题,通过一系列程序实例,分析了循环的构造过程。此后介绍了C语言其他控制结构及其使用。

第五章,C语言程序结构。本章讨论了C语言许多具有一般性的重要问题,主要是C程序结构,函数概念及有关的问题,预处理命令和预处理过程等。

第六章,数据对象的顺序组合:数组。介绍数组概念、定义和使用,数组的处理,数组与函数的关系,两维和多维数组等。

第七章,指针。首先介绍指针的概念和指针变量的使用,介绍了C语言中指针与数组的关系等,多维数组作为参数的通用函数等。而后讨论了动态存储管理,类型定义,指向函数的指针等一系列问题。

第八章,输入输出与文件。本章讨论了文件的概念,与输入输出有关的各种问题,标准库的输入输出功能,以及输入输出的程序设计问题。

第九章,结构及其他数据机制。介绍结构(struct)、联合(union)、枚举(enum)等数据定义机制的意义及在程序中的使用。随后简单介绍了链接结构的概念。

第十章,程序开发。本章讨论程序设计和开发中的许多一般性问题和技术。包括C程序的分块开发问题等。

第十一章,标准库函数。介绍标准库提供的各方面功能及其相关知识。

最后有几个附录和一个比较详细的索引。

本书以标准C语言为基础,有关内容不依赖于任何具体C语言系统。因此在这个课程中(本书阅读中)可用任何符合ANSI C标准的C系统作为程序工作环境。目前国内常用的微机上的各种C语言系统,工作站或其他计算机上的C系统都可以用。虽然软件厂商在不断推出新版本的程序开发环境,但从学习基本程序设计的角度看,新版本的开发环境未必比早些的版本有多大改善,但通常它们更复杂、占用更多的计算机资源,尤其是初学者入门更困难。由于本书的所有例子程序都按ANSI C标准书写,习题中不牵涉到任何具体的系统环境。因此本书的学习并不要求复杂的环境支持,建议读者使用比较简单基本的系统作为学习工具,例如国内使用较多的TURBO C 2.0系统等,一些公开的免费C语言系统等。本书的最后附了对TURBO C 2.0系统的简单使用说明。

我特别感谢北京大学数学学院和北京大学理科试验班参加过我的课程的同学们和参加过课程辅导的研究生们,是他们的思考和提出的问题给了我许多启示,使我更深入地理解了许多问题。我也要感谢我的家人与同事在这些年工作中给我的支持。

虽然本书包含了我几年的工作和思考,但书中难免有大的或小的错误,这些都由我个人负责。希望读者能把发现的问题告诉我,也希望同行们对本书提出宝贵意见。

裘宗燕

北京大学数学学院信息科学系,19991

20022003年修改