本书从计算机基础知识讲起,继而介绍标准C语言的内容。除此之外,书中还包含其他教材没有而C编程又必需的若干重要内容。
本书深入浅出,文字简练,将复杂的问题简单化,内容全面而篇幅不大;对各章节的重点、难点把握准确,处理得当;注重培养编程思维能力,对编程时易犯的错误,点评到位。书中对C语言中最重要的内容——函数、指针、数组、文件四部分的编写,比主流教材上升了一个层次。尤其是指针部分,全面纠正了多年以来主流教材中的若干错误,给出了明晰、准确的说法和定义。
本书作者讲授C语言二十多年,有丰富的编程和教学经验,对学生的思维方式和学习状况非常了解,对C语言的知识体系烂熟于心。在书中,作者奉献了自己对许多问题的独到见解。书中大量的编程经验和注意事项,蕴含着作者长期的积累,凝聚着C语言的精华。
本书非常适合作为高等学校各专业程序设计基础、C语言程序设计等课程的正式教材,也可作为自学教材或学习参考书。
C语言是高等学校计算机及相关专业必修的专业基础课,是培养学生算法思维能力和动手能力的主要课程,也是面向对象程序设计、数据结构等后续课程的先导课。学生对C语言的掌握情况很大程度上决定着大学四年的学习情况。
鉴于C语言的重要地位,近些年来出现了无数的C语言教材,但几乎所有教材在内容和顺序上都千篇一律,存在许多问题。有些问题是致命的,导致长期以来国内众多教师和学子对一些知识的理解出现严重偏差,使C语言的教与学走入误区。虽然有些教材在形式上做了不少改进,如案例教学法、启发式教学法等,但都是表面文章,核心内容并无变化,教材中的问题依然存在。
作者讲授C语言多年,对目前国内教材在诸多方面的缺陷和错误给广大学子造成的危害深感忧虑。曾几次动笔,都因懒惰而搁置。未能成书的另一个原因,是多年来一直觉得能等到一本较高质量、没有重大错误的教材,然而终无所见,于是,编写了本书。
编写本书的指导思想
(1) 针对刚入大学的新生,将C编程所需的一些必要的计算机知识纳入本书。
(2) 按符合学生认知规律的自然顺序安排章节,而不是为了所谓的“系统”、“全面”不顾及知识点的自然顺序把前后相关的所有内容都堆放在一起。那样做很容易把初学者的思维搞乱,因为对于一个初学者来说,理顺众多知识点之间的关系很难。
(3) 化繁为简、化整为零。重要的知识点单独写成一章,每章内容相对独立,与其他知识点关联少,条理清楚,易于初学者掌握。
(4) 对目前绝大多数教材都出现严重错误的“指针”一章的内容和绝大多数教材都语焉不详的“文件”一章的内容重点着墨。纠正主流教材中的诸多错误说法和错误代码,澄清若干似是而非的问题。
(5) 将作者多年积累的教学经验、对若干问题的独到见解、编程注意事项、典型例题和习题写到书中,奉献给广大师生和读者。
与其他教材相比,本书在以下几方面做了较大改进。
1. 对教材内容的改进
1) 增加了以下几部分的内容
要学好C语言,下面的知识是必要的,但几乎所有教材对以下内容都未涉及。[1]〖2〗深入浅出新编C程序设计教程[1]前言〖2〗(1) 计算机基础知识。绝大多数学校都把C语言放在大一的第一学期开设,对于没有任何计算机基础知识的新生来说,C语言的知识仿佛“天书”。因此,本书从计算机基础知识讲起。这些基础知识包括内存和内存地址的概念,二进制,不同数制之间的转换,原码、反码和补码的求法,计算机语言及语言处理过程等。
(2) 有关路径和输入输出重定向的概念。C语言中,很多地方需要用到路径和输入输出重定向的概念,故也把这两部分内容编入本书。其中路径部分放在第1章,作为选讲或自学的内容;输入输出重定向放在附录中,供需要的读者自行学习。
(3) 缓冲区及键盘缓冲区的概念。学习C语言的输入输出,缓冲区是个绕不开的话题。如果不知道数据从键盘到缓冲区的处理过程,就很难掌握输入输出,就很难解释为什么程序会出现那些意想不到的运行结果。
(4) 函数的作用和函数设计的原则。函数是被调用的,因此函数的适用性和灵活性是衡量一个函数优劣的重要指标。多数教材只注重讲解函数定义和函数调用的格式、函数参数传递的特点,对于函数的作用和设计原则(追求通用性、可利用率等)极少谈及。本书从函数返回值的设定以及参数设定两方面详细讲述函数设计的原则。
(5) 文件操作原理及相关细节问题。文件一章的内容非常重要,但又特别难懂。难懂的原因有三: 一是几乎所有教材都未给出文件操作的原理,学生知其然,不知其所以然;二是有几个概念特别容易混淆,如写数据有文本和二进制两种方式,文件分文本和二进制两类文件,文件的打开方式也分文本方式和二进制方式。所有教材都未明确指出它们之间有无关联,区别是什么,导致学生概念混乱;三是几乎所有的教材在介绍文件操作时都语焉不详,对一些重要内容不予讲解,导致学生一编程就出错,望文件而生畏。本书对上面所说问题均做了详细讲述并予以例证。
2) 纠正了主流教材中的若干错误
(1) 纠正了几乎所有教材都存在的关于指针的一些错误说法。例如,“指针就是地址”、“若有定义int a\[10\],*p=a;,则p指向数组a”、“若有定义int a\[3\]\[5\],*p=a;,则p是指向二维数组的指针”、“指向字符串的指针变量”、“数组名就是数组的首地址”、“&是取地址运算符”等错误说法。
(2) 对文件操作中的一些问题进行了纠正或澄清。例如,函数feof()何时返回非零值问题(多数教材所讲都是错的)、用二进制方式能否打开文本文件、用文本方式打开文件后能否以二进制方式向其中写数据等问题。
(3) 澄清了共用体变量能否初始化、共用体变量能否作为参数等问题。
2. 对各章节的内容分配及前后顺序都做了较大调整和优化
1) 对指针内容的分解
指针是C语言的精华,但指针又非常难学。因为C语言中指针的类型很多。如此多的类型本就容易混淆,一般教材又把它们全部放在一章中讲解,显得很全面、很系统。但学生要在一章中(两周的时间)弄懂如此多抽象难懂的内容,实在是勉为其难。实际效果表明,这样安排很不合理。也正是因为这样安排才使得指针如此难学。
本书将指针最重要的两个应用——用指针变量访问变量、用指针变量访问下标变量两部分抽出来作为单独的两章来讲解。其中,“用指针变量访问变量”一章放在函数之后、数组之前讲解;“用指针变量访问下标变量”一章放在数组之后讲解,其余内容放在“指针综述”一章中介绍。如此分解可化繁为简,具有重点突出,针对性强,易于接受等优点,也彰显了指针的这两个重要用途。另外,这样的设计也可把对指针的学习从短短一两周的时间扩展到前后约一个月的时间。较长时间的消化,有利于学生更好地理解指针、掌握指针。
2) 各章节顺序的调整
多数教材在以下章节的安排顺序上存在问题。
(1) 数组和指针的顺序问题。一般教材都是先讲数组,再讲指针。带来的问题就是,无法对数组名进行解释,于是产生了“数组名是个地址”的错误说法。实际上数组名在多数情况下都是一个指针。在不介绍指针的情况下,很难把数组一章的内容讲清、讲透。
先讲数组再讲指针,也无法讲明在数组名作为参数的情况下被调函数形参int x\[\]中的x是个指针变量,只好把它说成是“与实参数组具有相同地址的数组”,不仅难以令人信服,而且对很多现象(比如为什么x可以进行自增运算)也无法解释。
(2) 数组和函数的顺序问题。一般教材都是把函数放在数组之后讲解,原因是便于把“数组名作参数”放在函数一章中。看起来似乎归类得当,岂不知这样一来就掩盖了函数一章的重点。函数一章,最应该教给学生的是如何把函数设计得当、便于其他函数调用,只应突出这一重点。如果把数组问题也放在函数一章中,就会喧宾夺主,因为数组名作参数本身也是非常重要的一个知识点。
综上所述,最合适的顺序安排是函数、指针(1)、数组、指针(2)、指针综述。
本书的使用建议
建议理论授课学时数: 48~56。建议实验学时数: 24~32。
第1章计算机基础知识,若授课对象不是大一第一学期新生,已有基础,可以不讲,或只讲需要的部分。其中带星号的内容(路径及其表示)为选讲内容。
第16章编译预处理,未必到最后才讲,可根据情况放在适当时候讲解,如放在第8章之后。
本书适用对象: 高等院校本、专科所有开设程序设计基础或C语言程序设计课的学生,或自学C语言的读者。
其他说明
1. 本书所用编译器
本书讲解时兼顾Visual C++(简称VC)6.0和Turbo C 2.0,但程序主要是针对VC编写的,所有源程序都在VC中调试、运行过,例题中的运行结果都是在VC中得到的。
2. 例题和源代码
本书配套资料(可从www.tup.com.cn下载)中含有全部103个例题源代码,例题编号与源程序的编号一一对应。例如,例2.1的源代码对应资料中的源文件s2_1.c,若该例题有3种解法,则对应的源文件分别是s2_1_1.c、s2_1_2.c和s2_1_3.c。
本书的编写获2014年山东省普通高校应用型人才培养专业发展支持计划项目和2012年山东省高等学校教学改革项目的资助。我校专业共建合作伙伴——浪潮优派科技教育有限公司总裁邵长臣先生审阅了全书,并提出很多宝贵的意见,在此致以诚挚的谢意。原达教授、谢青松教授也对本书的编写给予热情帮助和大力支持,在此向以上两位深表谢意。此外,本书的编写参考了大量的书籍和文献资料,谨向这些书籍和文献资料的作者表示感谢。本书在编写出版过程中也得到了清华大学出版社的大力支持和帮助,在此一并表示感谢。
由于时间仓促和作者水平所限,书中难免疏漏和欠妥之处,请各位专家、读者不吝指正。
作者
第1章计算机基础知识1
1.1计算机的硬件组成1
1.1.1运算器1
1.1.2控制器1
1.1.3存储器1
1.1.4输入设备3
1.1.5输出设备3
1.2数制及数制间的转换3
1.2.1二进制3
1.2.2八进制5
1.2.3十六进制5
1.3原码、反码和补码6
1.3.1原码6
1.3.2反码6
1.3.3补码6
1.4路径及其表示6
1.4.1路径的概念6
1.4.2当前盘和当前目录7
1.4.3绝对路径和相对路径7
1.5计算机语言8
1.5.1机器语言8
1.5.2汇编语言9
1.5.3高级语言10
1.6算法11
1.6.1算法的概念11
1.6.2算法的特性12
1.6.3算法的表示12
1.6.4程序的3种基本结构13[1]〖2〗深入浅出新编C程序设计教程[1]目录〖2〗习题114
第2章C程序和C编译器简介16
2.1C语言及C标准简介16
2.1.1C语言的出现16
2.1.2C语言的特点16
2.1.3C标准17
2.2简单的C程序18
2.3C程序的构成22
2.4C编译器及操作简介24
2.4.1Turbo C 2.0编程环境及常用操作简介24
2.4.2Visual C++6.0编程环境及常用操作简介28
习题233
第3章C编程基础知识35
3.1常量和变量35
3.1.1常量35
3.1.2变量35
3.2基本数据类型40
3.2.1整型数据40
3.2.2实型数据42
3.2.3字符型数据45
3.2.4字符串47
3.3符号常量和常变量48
3.3.1符号常量48
3.3.2常变量48
3.4运算符和表达式49
3.4.1算术运算符49
3.4.2赋值运算符和赋值表达式50
3.4.3自增自减运算符51
3.4.4逗号运算符和逗号表达式53
3.4.5类型转换运算符54
3.5数据的类型转换55
习题355
第4章顺序结构程序设计59
4.1赋值语句59
4.1.1赋值语句及其执行过程59
4.1.2赋值的几种数据处理方式59
4.2输入输出函数63
4.2.1缓冲区的概念及作用63
4.2.2getchar()和putchar()64
4.2.3printf()和scanf()65
4.3顺序结构程序设计举例70
习题472
第5章选择结构程序设计76
5.1关系运算符和关系表达式76
5.1.1关系运算符76
5.1.2关系表达式76
5.2逻辑运算符和逻辑表达式77
5.2.1逻辑运算符77
5.2.2逻辑表达式78
5.3if语句79
5.3.1if语句的格式79
5.3.2if语句的使用说明80
5.3.3嵌套的if语句83
5.3.4if语句应用举例85
5.3.5if语句编程的常见问题87
5.4条件运算符和条件表达式92
5.5switch语句93
5.5.1switch语句的格式及执行过程94
5.5.2switch语句应用举例96
5.5.3switch语句编程的常见错误97
习题598
第6章循环结构程序设计104
6.1循环及其实现思想104
6.2循环语句105
6.2.1while循环105
6.2.2dowhile循环107
6.2.3for循环108
6.2.43种循环的比较110
6.3循环的控制111
6.3.1计数器控制循环和其他条件控制循环111
6.3.2break和continue112
6.3.3循环结束后循环变量的值与终值的比较115
6.4多重循环116
6.5循环编程举例117
习题6126
第7章函数132
7.1函数的作用132
7.2函数的定义134
7.2.1函数定义的格式134
7.2.2函数的返回值134
7.2.3函数参数的设置138
7.3函数的调用140
7.3.1函数调用前的声明140
7.3.2函数调用的方式142
7.4函数的参数传递143
7.4.1形参与实参143
7.4.2参数的传递143
7.4.3参数传递的单向性144
7.5函数的嵌套调用145
7.6递归函数146
7.6.1递归的条件146
7.6.2递归函数的执行过程147
7.6.3递归与迭代149
7.7函数编程举例150
7.8内部函数和外部函数153
习题7154
第8章变量的作用域和存储类别158
8.1变量的作用域158
8.1.1局部变量158
8.1.2全局变量158
8.2同名变量的辨析160
8.3变量的存储类别和生存期162
8.3.1内存的存储区域162
8.3.2动态变量162
8.3.3静态变量163
8.4变量的作用域和生存期164
习题8165
第9章用指针变量访问变量168
9.1指针和指针变量168
9.1.1指针和指针变量的概念168
9.1.2直接寻址和间接寻址169
9.1.3指针变量的值、地址及类型171
9.2通过指针变量访问变量171
9.2.1指针变量的定义171
9.2.2指针变量的赋值172
9.2.3通过指针变量间接访问一个变量173
9.3指针变量在函数传递中的作用173
习题9178
第10章数组181
10.1一维数组181
10.1.1一维数组的定义181
10.1.2一维数组的元素构成及一维数组的存储结构182
10.1.3数组名的指针类型182
10.1.4数组元素的表示方法183
10.1.5一维数组的引用184
10.1.6一维数组的初始化186
10.1.7一维数组应用举例186
10.2二维数组191
10.2.1二维数组的定义191
10.2.2二维数组的元素构成及二维数组的存储结构192
10.2.3二维数组名的指针类型192
10.2.4二维数组中下标变量的表示方法193
10.2.5二维数组的引用194
10.2.6二维数组的初始化195
10.2.7二维数组应用举例195
10.3字符数组和字符串处理函数196
10.3.1字符数组196
10.3.2字符串处理函数197
10.3.3字符数组应用举例201
习题10203
第11章用指针变量访问下标变量208
11.1用指针变量访问下标变量的方法208
11.1.1知识回顾208
11.1.2用指针变量访问一维数组中的下标变量208
11.1.3用指针变量访问二维数组中的下标变量210
11.2用指针变量访问下标变量的适用场合211
习题11214
第12章指针综述218
12.1指针类型简介218
12.2指向变量的指针219
12.2.1指向变量的不可变指针219
12.2.2指向变量的指针变量219
12.3指向数组的指针220
12.3.1指向一维数组的不可变指针220
12.3.2指向一维数组的指针变量221
12.3.3指向一维数组的指针变量的适用场合222
12.4指针与字符串223
12.4.1字符串的表示方式223
12.4.2用指针变量处理字符串225
12.5指针与函数227
12.5.1函数的入口地址227
12.5.2指向函数的指针变量227
12.5.3指向函数的指针变量的作用228
12.5.4指针函数229
12.6指针数组230
12.6.1指针数组的定义230
12.6.2指针数组的引用231
12.6.3指针数组应用举例231
12.7指向指针变量的指针231
12.7.1指向指针变量的不可变指针231
12.7.2指向指针变量的指针变量232
12.7.3应用举例232
12.8带参数的main()函数235
12.8.1C语言对main()函数参数的规定235
12.8.2带参数main()函数的作用235
12.8.3带参数的main()函数的执行过程236
12.8.4程序举例236
12.9动态内存分配237
12.9.1动态内存分配函数237
12.9.2动态内存分配举例238
习题12239
第13章数据类型的自定义244
13.1结构体的定义和结构体变量的定义244
13.1.1结构体的概念和结构体的定义244
13.1.2结构体变量的定义和空间分配246
13.1.3结构体变量的初始化248
13.1.4结构体数组的定义和初始化249
13.2结构体变量的引用249
13.2.1结构体变量的引用方法249
13.2.2结构体变量引用举例250
13.3用指针变量操作结构体变量251
13.3.1为什么要通过指针变量访问结构体变量251
13.3.2应用举例252
13.4链表及链表操作简介253
13.4.1链表的概念253
13.4.2使用链表的优点254
13.4.3链表操作简介254
13.5共用体259
13.5.1共用体的概念259
13.5.2共用体的作用260
13.5.3共用体及共用体变量的定义261
13.5.4共用体变量(数组)的初始化262
13.5.5共用体变量的引用262
13.6枚举类型263
13.6.1枚举类型的定义263
13.6.2枚举变量的定义264
13.6.3枚举变量的使用264
13.6.4枚举应用举例264
13.7用typedef定义类型别名265
习题13267
第14章位运算270
14.1C语言中的位运算符270
14.2位运算及应用271
14.2.1按位与271
14.2.2按位或272
14.2.3异或273
14.2.4取反274
14.2.5左移274
14.2.6右移275
习题14276
第15章文件278
15.1文件及相关的概念278
15.1.1文件的范畴278
15.1.2文件中存储数据的两种方式278
15.1.3文件的种类279
15.1.4文件操作函数及缓冲区的概念280
15.2文件读写的原理281
15.3文件的读写位置指针和文件结束标志282
15.3.1读写位置指针282
15.3.2文件结束标志282
15.4文件的打开和关闭283
15.4.1文件的打开283
15.4.2文件的关闭289
15.5文件的读写290
15.5.1fgetc()和fputc()291
15.5.2fread()和fwrite()293
15.5.3fgets()和fputs()297
15.5.4fscanf()和fprintf()298
15.6读写位置指针的移动和定位300
15.6.1移动读写位置指针的函数300
15.6.2两个与读写位置指针有关的函数301
15.7文件的出错检测302
15.8文件操作举例303
习题15307
第16章编译预处理310
16.1宏定义310
16.1.1无参宏定义310
16.1.2有参宏定义311
16.1.3嵌套的宏定义312
16.2文件包含312
16.2.1文件包含的格式312
16.2.2文件包含的作用313
16.2.3文件包含两种格式的区别313
16.3条件编译314
16.3.1条件编译的格式314
16.3.2条件编译应用举例316
习题16317
附录AC语言规约320
附录B输入输出重定向322
附录CC语言的关键字325
附录D常用字符与ASCII码对照表326
附录E运算符的优先级和结合性327
附录F常用库函数329
参考文献334