第2版前言 本书自2015年出版以来,得到很多老师和同学的认可。青年教师通过本书的教学,大大提高了程序设计课程的教学能力;大学一年级的学生通过本书的学习,对程序设计、计算机科学产生了浓厚的兴趣,开启了他们程序设计和软件开发的人生之旅。由于本书严格的在线评测程序设计风格,以问题求解为核心的软件工程思想体系,以及特别注重分析问题、解决问题能力的培养,专业的程序设计基本功的训练等显著特征,2017年被福建省教育厅评为福建省特色优秀本科教材,本人所在的教学团队——福建工程学院信息工程与计算机学院软件工程教研室被福建工程学院授予教学成果二等奖,在这里非常感谢团队的所有成员。 随着互联网技术的发展,特别是移动互联网的发展,人们的学习方式也发生了根本的变化,各种各样的在线学习平台纷至沓来,原来需要在实验室里,在计算机上才能做的事情,现在通过手机就可以完成了。本书与第1版相比,没有在内容上做大的改动,但在技术阐述上做了一些改写,从而方便了老师教与学生学,每个问题的分析求解都给出了“微课”视频,每个问题的求解程序都可以通过手机“扫码”查看。学生随时随地都可以看视频资料,读程序源码,甚至利用手机在线编译,查看运行结果。作者相信,会有更多的老师和学生喜欢本书,非常欢迎大家与作者进行交流,并提出宝贵的意见和建议。 这里说明一下使用手机扫描书中的二维码获取源代码问题。如果只是查看源代码,扫二维码后即可直接查看。如果想在手机上编译运行,建议先在手机上下载一个“C语言编译器”App,一般来说,运行App之后呈现的是可以输入代码的编辑窗口,这时切换到已经扫码打开的源代码文件,选中所有的源代码并复制(当代码比较长的时候,可能要分几次复制),然后再切换回编辑窗口,粘贴所复制的代码,然后点击该编译器界面上的“运行”按钮运行程序。读者也可以选择“发送到邮箱”项目,再从邮箱里下载源代码后在计算机上编译运行。 另外,作者是第一次在没有学生听课的情况下,面对计算机讲课并录制视频,视频效果不太理想的地方还请读者谅解。若有错误或不妥之处,请读者批评指正,在此表示衷心的感谢。 本书在修订过程中,不仅得到福建工程学院计算机科学与数学学院软件工程教研室教学团队的支持,还得到四川工业科技学院电子信息与计算机工程学院计算机教研室教学团队的认可,在此一并表示感谢! 鲍春波2020年春于四川德阳第1版前言 “高级语言程序设计”是高等院校计算机相关专业开设的第一门计算机课程,它不仅是专业基础课,要为后续课程打基础,还肩负着激发学生的学习兴趣、培养学生的专业基本功、培养学生分析问题解决问题的能力,引导学生成为合格的专业人才(即启蒙、入门)等重任。特别是应用技术型大学、卓越工程师教育培养计划、国际工程教育认证的兴起,对计算机专业人才的培养提出了更高的要求,使得这门课程的重要性更加凸显。作者在多年的教学实践和工程实践中一直在思考一个问题:计算机专业的第一门课到底上什么、怎么上才能符合卓越工程师教育培养计划和培养应用工程型人才,特别是国际型计算机人才的培养目标?带着这样的问题,以福建工程学院校级精品课程建设为平台,不断地进行理论教学和实验教学改革,吸收和学习国内外先进的教学理念和方法。本书和配套的《问题求解与程序设计习题解答和实验指导》是作者多年教学改革的积累和总结。 本书的特点 本书的每章开始列出了几点学习目标,引出了该章要讨论的话题和要解决的问题。每章的最后都有一个小结,以及若干概念复习题、填空题和在线评测题,还有一个比较综合的项目设计。除此之外,本书还有下面一些突出的特点。 1. 以问题求解为核心 学习程序设计的目的就是要解决实际问题,就是要训练和提高分析问题和解决问题的能力。因此本书精心组织了四十多个实际案例问题。每个章节都围绕解决某个或某类案例问题而展开。把各种语法现象和编程技巧与规范融入解决这个问题的具体过程中。在解决问题的过程中学习程序设计的方法,训练程序设计的功夫。对于每个案例,经过分析、设计之后,给出完整的程序实现清单,教师或学生可以编译运行程序,先从感性上了解程序的输入输出和运行结果,然后再详细展开相关的知识点。 2. 融入软件工程的思想 对于每个案例问题,首先按照问题描述和输入输出格式的要求进行全面分析,明确要做什么,考虑各种可能的情况。对每一种情况都给出具体的算法设计方案(伪码或流程图)、对应的代码实现(程序清单),其次对程序或算法用一组测试用例进行运行测试(这个运行测试是实时演示,教材中省略)。不管案例问题是大还是小,都严格按照这样的过程展开,进行强化训练。 3. 遵循循序渐进的原则 传统的教材都是比较集中地介绍各种语法现象, 学生比较难以接受。本书采用循序渐进的原则,螺旋式展开,在问题求解需要的时候才介绍语法规范和注意事项。具体表现在以下几个方面。 对于数据类型和运算来说,在第2章只是介绍了整型数据和浮点型数据、算术运算和赋值运算。在第3章介绍了字符型数据、布尔型数据,关系运算、逻辑运算和条件运算。在第4章介绍了自增自减运算和复合赋值运算。 对于变量的存储类别和作用域来说,先在5.1.3节初步认识一下,然后在5.2节介绍局部自动变量和局部静态变量及单文件内的外部变量。在5.4.3节进一步介绍应用程序范围内(多文件之间)的全局变量,还在5.4.4节介绍了单文件范围内的静态函数——私有函数。 对于指针,从第2章程序设计入门时的scanf函数中变量取地址,到第6章一维数组名代表的首地址和二维数组名代表的首地址(行地址构成的一维数组)——常指针,再到第7章一般的指针变量出现,以及进一步指向一维数组、指向二维数组的行和列、指向字符串、指向函数的指针讨论等,最后再到第8章的指向结构对象的指针,前后相互呼应。 4. 程序设计在线评测 在线评测(Online Judge)本来是为各种程序设计竞赛提供的平台,通过几年来的教学实践,作者觉得在线评测用于程序设计类课程的教学效果很好。首先,由于每道在线评测的题目都精心设计了一组测试用例,学生要完成它,必须严格按照输入输出样例的格式要求,仔细设计问题的求解算法。在设计过程中必须考虑各种可能的情况,不然就会导致部分测试用例不能通过。因此对于学生来说,非常有利于培养学生的专业素质,提高学生程序设计的能力。其次,由于是在线评测,学生提交作业之后会立即得到评测结果,因此如果在线评测的结果是Accepted,学生也会产生学习兴趣,带来一定的成就感。如果在线评测的结果是错误的,也会马上知道是什么类型的错误,学生也会很快改正。对于教师来说,虽然需要比较多的准备时间,但是题目一旦设计好,基本就不用人工评阅程序了。当然教师也应该抽查学生在线提交的作业,包括正确的和不正确的,从中发现问题。最后,在线评测与传统的作业完成方式相比更能训练学生的动手操作能力、问题求解能力。本书从第2章起,每章都设计了十余道在线评测题目,全书总计包括一百多道在线评测题目。 5. 项目设计 从第2章起,每章最后都至少给出了一个项目设计题目。项目设计题目是一个规模相对比较大的题目,因此,最好以小组为单位集体完成。组员之间彼此进行分工合作,这样可以培养学生的团队协作精神。在设计的时候,如果采用集成环境最好建立一个工程,特别是当项目规模比较大的时候更应该建立工程,在工程中可以方便地管理多个文件。 6. 习题解答与实验指导 本书配备了“习题解答与实验指导”,共包含五部分内容。第一部分是本书各章习题的参考答案,包括概念填空题和在线评测题目的参考答案。第二部分是实验指导,介绍了用计算机进行问题求解所需要的环境是如何搭建的。从编译器、编辑器到调试器,从命令行环境到集成环境分别给予介绍。在第5章还介绍了一个gcc编译器支持的图形库grx,初学者在Windows环境下也能比较容易地进行图形程序设计。第三部分是实验,包括与本书各章对应的实验内容。每个实验基本上分为三小节: 第一小节是程序基础练习,主要做一些阅读程序练习和修改程序练习,通过练习使学生理解相关的基本概念;第二小节是通过修改调试有错误的程序,训练学生的程序调试能力;第三小节是完整的问题求解,针对问题描述和测试用例的要求,给出完整的程序设计解决方案。第四部分是实验解答,限于篇幅,只对每个实验中程序基础练习部分给出了参考答案,对程序改错部分的每个题目都归纳出了几个知识点,分析了出错的原因。第五部分是课程设计,包括课程设计的目的、要求,课程设计的题目和评分标准,以及课程设计报告的书写格式。课程设计的题目分为A、B两档,把学生按“高级语言程序设计”课程的成绩分成两组,这样做的目的是争取让每个同学都能通过课程设计得到比较充分的锻炼和提高。 7. 课程平台 随着互联网的快速发展,特别是5G高速网络的到来,在线学习已经越来越普及。在线编译器和在线评测系统成为程序设计学习的热门平台。此外,如果想自己搭建一个含有在线评测的自主学习平台,也可以安装moodle系统,不过要另外安装一个onlinejudge插件。 8. 开源软件 本教材使用的软件均为开源软件,包括moodle平台、gcc编译器、gdb调试器、grx图形库及CodeBlocks集成开发环境。教育学生树立版权意识,杜绝盗版,鼓励学生使用开源软件。 9. 本书对部分内容加强了讨论 本书内容包括一般高级语言程序设计教材的全部内容,此外还特别讨论了大整数处理问题、函数接口的设计与实现、建立自己的库、使用函数获得动态申请的内存、用指针访问二维数组元素的各种方法、位运算的应用、gcc编译器支持的C语言图形程序设计、专业编辑器vim的使用、命令行环境等问题,一般的教科书很少涉及这些问题。 10. 例题经过编译测试 本书所有例题的C语言源程序都已经过最新版本的gcc编译器编译测试,因此完全符合C99标准。事实上,所有的源程序都可以直接作为C++源程序,用gcc或g++编译器编译运行。 本书代码对源程序进行了删减,删除了源代码文件中出于方便阅读目的而添加的空行,左大括号调到了上一行的末尾,故现在所列代码行号有跳跃,特此说明。 本书的主要内容 全书共有10章,各章内容概述如下。 第1章计算机与程序设计。本章介绍了计算机的工作原理和它的快速计算能力、逻辑判断能力,特别强调这些能力都要通过存储程序来实现,因此进一步讨论了如何存储程序和数据、计算机系统软件程序的重要性。为了使学生对程序有一个感性认识并产生一定的兴趣,精选了几个典型的C/C++结构化程序,包括一个命令行的猜数游戏程序、一个图形绘制程序、一个窗口程序、一个简单的嵌入式程序和一个网络应用程序。最后说明了写程序、开发软件要讲究方法,介绍了结构化方法和面向对象方法。程序设计还需要一个基本的开发环境,包括编辑器、编译器和调试器。对于编辑器,鼓励学生学习使用专业的vim或者emacs编辑器。对于编译器,提倡使用开源的、跨平台gcc/g++编译器。调试器使用gdb。同时要求计算机专业的学生必须练好打字功夫,能够熟练地使用操作系统的命令窗口。 第2章数据类型与变量——程序设计入门。本章通过六个问题的分析求解,使读者初步认识程序设计到底是干什么的。通过问“在屏幕上输出文字信息”的问题,介绍了C/C++结构化程序设计的基本框架及标准输出函数。通过 “计算两个固定整数的和与积”问题,引出了常量与变量、整型数据、算术运算、赋值运算等概念。通过“计算任意两个整数的和与积”问题的分析求解,介绍了标准输入函数、测试用例和用流程图表示顺序程序结构的方法。通过“温度转换”问题的求解过程说明了变量初始化和运算的优先级和结合性的重要性。通过“求两个整数的平均值”问题引出了浮点型数据以及不同的数据类型之间的转换等重要概念。通过“求圆的周长和面积”介绍了宏常量和带参数的宏的用法。 第3章判断与决策——选择程序设计。本章通过五个问题的求解,介绍了具有判断决策能力的程序该如何设计实现。通过“让成绩合格的学生通过”问题引出了逻辑常量、布尔型数据、关系运算、判断条件的各种表达形式,以及C/C++中进行逻辑判断的单分支选择结构。通过 “按成绩把学生分成两组”问题引出双分支选择结构和条件运算,同时分析了用两个单分支求解同样问题的情况。通过“按成绩把学生分成多组(百分制)”问题的分析求解,自然而然地引出选择结构的嵌套,同时给出了一种新的表达方式——switchcase结构。通过“按成绩把学生分成多组(五级制)”引出了字符型数据的表达方法。通过“判断闰年问题”引出了逻辑运算,从而给出了复杂判断条件的表达方法。 第4章重复与迭代——循环程序设计。本章通过七个问题的分析求解,阐述了三种循环程序结构和三种控制循环的方法。通过“打印规则图形”问题分析了如何从重复的角度观察问题,使读者认识到发现问题中包含的重复因素的重要性,引出了while循环结构及计数控制循环的方法。通过“自然数求和与阶乘计算”问题引出了与while等价的for循环结构。通过“简单的学生成绩统计”问题的分析引出了标记控制(按CtrlZ组合键或输入特殊的值)循环的方法,因为这时不知道重复的次数。数据输入/输出可以是键盘和屏幕,也可以重定向到文件,这样更方便重复测试。通过“计算2的算术平方根”问题的分析求解,介绍了误差精度控制循环的方法。通过“打印九九乘法表”问题介绍了循环嵌套和穷举法。通过“素数判断”和“处理有效成绩”问题的分析求解引入了break、continue的用法,分析了goto语句的利弊。通过“随机游戏模拟”问题介绍了如何产生随机数和自顶向下逐步求精的分析方法。最后对结构化进行了总结,指出任何问题都可以使用顺序结构、选择结构和循环结构通过堆叠和嵌套的方法表示出来。 第5章分而治之——模块化程序设计。本章循序渐进地介绍了模块化程序设计的思想和方法。通过“再次讨论猜数游戏模拟问题”,采用自顶向下逐步求精的分析过程把问题划分为模块,描述了模块化程序设计的思想。然后进一步介绍了C/C++语言表达模块的基本单位——函数,包括函数的定义、声明、调用和函数测试的基本方法。通过“判断问题”的分析求解进一步加深了函数的概念和函数的模块化功能,并且进一步探讨了函数调用的内部机制及变量的存储类别和作用域在函数调用过程中是如何体现的。接下来通过“问题的递归描述”介绍了递归函数的定义和递归调用的过程。通过“一个简单的绘图函数库”问题,使读者进入了更高的层次,如何把一组函数做成一个库接口,即如何设计接口,如何实现接口,如何使用接口及如何建立一个静态库或者动态库。在这个过程中,介绍了多文件之间的全局变量和文件内部的私有函数的声明方法。然后通过“学生成绩管理系统”问题的分析和设计,介绍了大规模问题的计算机求解方法,包括命令行编译链接多文件、集成环境下建立一个工程,以及使用make工具和makefile文件编译链接多文件的系统等。 第6章批量数据处理——数组程序设计。本章通过典型的批量数据的排序和查找引出了数组的概念和用法。通过“一门课程的成绩排序”问题的分析,一组数据排序必须首先解决如何存储它们,然后才是怎么排序。通过对排序数据的特点分析,引出了用一维数组存储数据的方法。详细介绍了数组的声明、初始化、元素的引用等。通过“三门课程成绩按总分排序”问题引出了二维数组,详细分析了二维数组与一维数组的异同,特别是一维数组名和二维数组名在逻辑上所代表的含义的不同。由于数组名有特别的含义,因此数组作为函数的参数也有特别的效果。通过两个排序问题的求解,介绍了交换排序、选择排序的算法,还提到了冒泡排序和插入排序。通过“在成绩单中查找某人的成绩”问题的分析,引出了字符数组、字符串和字符串数组。字符串是一类特殊的数据,常常要对它们进行各种各样的操作,在这个问题的求解过程中还介绍了标准库中提供的字符和字符串操作的各种函数的用法,同时还介绍了典型的查找算法——线性查找和折半查找。最后通过分析“大整数计算”问题,用数组模拟了小学生列竖式进行加减的过程,实现了大整数相加的算法。 第7章内存单元的地址——指针程序设计。本章详细介绍了用内存单元的地址间接访问变量、数组、字符串、函数的重要意义和方法。通过“用函数实现两个变量交换”的问题,分析了怎么才能做到用一个函数交换两个变量的值,通过与数组作为函数的参数的作用类比,发现只有用变量对应的内存单元的地址作为函数的参数才能在函数中交换两个变量的值。这样引出了指针的概念和指针变量的声明及引用。通过“再次讨论批量数据处理问题”,介绍了如何用指针间接访问数组元素,仔细讨论了指针偏移和指针位移的方法。通过“再次讨论二维批量数据处理问题”,详细分析讨论了用指针访问二维数组的元素的方法。一是直接使用二维数组名本身这个常指针访问二维数组的元素;二是把二维数组看成是一维数组的一维数组,用一个行指针先访问到行,再访问到列,通过二次间接运算访问二维数组的元素;三是把二维数组看成是一个一维数组,用一个列指针逐列访问二维数组的元素;四是用一个二级指针指向一个指针数组(每个指针指向二维数组的行),逐行访问二维数组的元素。通过“一个通用排序函数”问题介绍了指向函数的指针作为函数的参数的重要意义。通过“再次讨论字符串”问题介绍了字符型指针指向字符串常量和指向字符型数组的不同,字符型指针数组指向的一组字符串排序在排序过程中可以只交换指针。通过“应用程序运行时提供参数”问题介绍了含有参数的main( int argc, char *argv[ ])。通过“数据规模未知的问题求解”问题介绍了动态申请内存的库函数,以动态申请单个变量需要的内存、动态申请一维、二维数组为例介绍动态内存申请的方法。特别讨论了如何定义一个能够动态申请空间的函数,通过函数的参数或返回值得到所申请的空间。特别强调了C语言函数的参数传递无论是传普通的变量,还是传地址或指针,都是单向传值。为了便于将来数据结构课程的学习,这里还介绍了C++中的传引用,使用传引用可以使指针降一级。 第8章客观对象的描述——结构程序设计。本章介绍了C语言描述客观对象的方法。通过“基于对象的学生成绩管理”问题的分析引出了C语言描述对象的结构类型。系统地介绍了结构类型的定义方法、用结构类型创建对象(变量)的方法,实现了基于学生成绩结构类型的学生成绩管理,其中学生结构类型作为自定义的一种类型跟编译系统内置的类型一样,可以声明结构类型的数组,可以用指针指向结构类型的对象和结构类型的数组,指出用结构类型的数组作为函数的参数时一般用指针。通过“基于链表的学生成绩管理”问题的分析,引入了自引用结构,自引用结构创建的对象可以彼此用一个指针链接起来,形成一个对象链表。比较了结构对象数组与结构对象链表两种存储结构的优缺点。通过“志愿者管理”问题的分析与求解,引入了联合类型的定义与用法。通过“洗牌和发牌模拟问题”的分析与求解,给出了枚举类型的定义和用法。 第9章数据的持久存储——文件程序设计。本章首先回顾了数据的变量存储、数组存储甚至是链表存储,它们都具有易失性,引出了数据要持久存储的文件机制。通过“文件复制”问题的求解,介绍了文件格式(文本和二进制)、文件操作的一般步骤、文件指针、缓冲文件系统的概念及文件的各种打开方式。分别用字符读写和字符串行读写设计实现了文件复制问题。通过“把学生成绩数据保存到文件中”的问题求解介绍了文件的格式化读写、块读写(含顺序读写和随机读写)的方法,在此基础上,指出了文件版的学生成绩管理系统的实现问题。 第10章位运算——低级程序设计。本章介绍了在加密解密算法、图形图像处理和嵌入式系统开发等方面应用非常广泛的基于“位”操作的低级程序设计。通过 “网络IP地址的表示”问题介绍了整型数据按位左移右移、按位取反和按位与。通过 “加密解密问题”的分析求解介绍了按位或和按位异或。通过 “一个图形类型的优化问题”介绍了位段的概念和用法。在位运算的讨论过程中,特别强调每种位运算的特殊作用。 建议教学安排 章节理论学时实验学时第1章计算机与程序设计22第2章数据类型与变量——程序设计入门42第3章判断与决策——选择程序设计62第4章重复与迭代——循环程序设计62第5章分而治之——模块化程序设计62第6章批量数据处理——数组程序设计62第7章内存单元的地址——指针程序设计62第8章客观对象的描述——结构程序设计42第9章数据的持久存储——文件程序设计22第10章位运算——低级程序设计22合计4420在本书的写作过程中,福建工程学院信息科学与工程学院软件工程教研室主任林芳副教授审阅了初稿,对本书提出了宝贵的建议,并组织教研室相关授课老师讨论了本书的教学内容体系和方法,得到了大家的一致认可,在此表示衷心的感谢。福州大学数计学院谢丽聪副教授对本书的内容体系也给予了充分的认可,在此表示感谢。由于作者水平有限,书中难免存在这样或那样的错误,恳请广大读者批评指正。 鲍春波2015年元旦于福建工程学院