189 8069 5689

C语言入门经典(第5版)

(第 5 版)
: 本书中文简体字版由 Apress 出版公司授权清华大学出版社出版。未经出版者书面许可,不得以任何方
式复制或抄袭本书内容。
北京市版权局著作权合同登记号 图字: 01-2013-5119
本书封面贴有清华大学出版社防伪标签,无标签者不得销售。
版权所有,侵权必究。侵权举报电话: 图书在版编目 数据
C 语言入门经典(第 5 版) / (美) 霍尔顿(Horton, I.) 著;杨浩 译. —北京:清华大学出版社, 2013
(2018.5 重印)
书名原文: Beginning C, Fifth Edition
ISBN 978-7-302-34341-7
Ⅰ. ①C… Ⅱ. ①霍… ②杨… Ⅲ. ①C 语言—程序设计 Ⅳ. ①TP312
中国版本图书馆 CIP 数据核字(2013)第 255156 号
责任编辑:王 军 于 平
装帧设计:牛艳敏
责任校对:邱晓玉
责任印制:沈 露
出版发行:清华大学出版社
网 址: http://www.tup.com.cn, http://www.wqbook.com
地 址:北京清华大学学研大厦 A 座 邮 编: 100084
社 总 机: 010-62770175 邮 购: 010-62786544
投稿与读者服务: 010-62776969, c-service@tup.tsinghua.edu.cn
质 量 反 馈: 010-62772015, zhiliang@tup.tsinghua.edu.cn
印 刷 者:清华大学印刷厂
装 订 者:三河市溧源装订厂
经 销:全国新华书店
开 本: 185mm×260mm 印 张: 37.75 字 数: 872 千字
版 次: 2013 年 11 月第 1 版 印 次: 2018 年 5 月第 18 次印刷
印 数: 62001~67000
定 价: 79.80 元
————————————————————————————————————————————
产品编号: 052455-02
原本是一名数学家,因听闻信息技术工作轻松且收入丰厚而踏足其中。
尽管现实情况常常是工作辛苦且收入相对一般, 但他至今依然坚持从事计算机工作。 Ivor
在不同的时期从事过各种类型的工作,包括程序设计、系统设计、咨询顾问以及管理和
实现一些颇为复杂的项目。 Ivor 对于将计算机系统设计和实现应用在各种行业工程设计
和运营管理方面有着十分丰富的经验。他能够运用多种编程语言开发特定用途的应用程
序,同时还为科研人员和工程人员提供教学,以帮助他们完成这类工作。多年来,他一
直撰写编程方面的书籍,近期作品包括 C、 C++和 Java 教程。在写书与指导他人之余,
一般他会选择钓鱼、旅行和享受生活。
是一名来自比利时的软件工程师。他毕业于比利时天主教鲁汶大
学(Catholic University of Leuven),并拥有该校的计算机工程学硕士学位。一年后,他以
优异成绩获得了同一所大学的人工智能专业硕士学位。毕业后, Marc 开始在一家名为
Ordina Belgium 的软件咨询公司工作。作为一名咨询师,他主要为西门子及诺基亚西门
子网络公司提供服务, 工作内容包括帮助电信运营商在 Solaris 上运行关键性的 2G 与 3G
软件。这项工作需要身处国际范围的团队(跨度从南美地区和美国到欧洲、中东地区、非
洲以及亚洲)中完成。现在, Marc 在 Nikon Metrology 从事 3D 激光扫描软件开发工作。
Marc 在 C/C++方面经验丰富,尤其精通 Microsoft VC++和 MFC 框架。此外, Marc
也喜爱 C#,并使用 PHP 创建网页。除了主要对 Windows 开发感兴趣之外, Marc 还对开
发 Linux 平台上 24/7 全天候运行的 C++程序颇有心得(例如, EIB 家庭自动化软件)。
自 2007 年 4 月起,Marc 就因他在 Visual C++方面的丰富经验而屡屡荣获每年的 Microsoft
的年度 MVP(Most Valuable Professional,最有价值专家)奖。
Marc 是比利时 C++用户群组(www.becpp.org)的创始人,并经常以 Marc G 的代号活
跃在 CodeGuru 论坛中。他还创建了一些免费软件和共享软件,并发布在了他的网站
www.nuonsoft.com 上。此外, Marc 还在 www.nuonsoft.com/blog/上维护自己的博客。
作者只不过是一个大型团队中将书复印成册之人。我想感谢整个 Apress 编辑部与产
品组自始至终的帮助与支持。我要感谢 Jonathan Gennick 对于启动本书新版本所做的努力,
感谢 Jill Balzano 在整个编辑过程中耐心地帮助解决我遇到的各种难题。
我还要感谢我的技术编辑 Marc Gregoire,感谢他帮助审核文字和检查所有的代码片
段与示例。他找错的本领实在了得,他的许多建设性的评论与深思熟虑的建议无疑使本
书变成了一本更好的教程。
欢迎使用《C 语言入门经典(第 5 版)》。研读本书,你就可以成为一位称职的 C 语言
程序员。从许多方面来说, C 语言都是学习程序设计的理想起步语言。 C 语言很简洁,
因此无须学习大量的语法便能够开始编写真正的应用程序。除了简明易学以外,它还是
一门功能非常强大的语言,并被专业人士广泛应用在各种领域。 C 语言的强大之处主要
体现在,它能够应用于各类层次的开发中,从设备驱动程序和操作系统组件到大规模应
用程序,它都能胜任。此外, C 语言还可以适用于相对较新的手机应用程序开发上。
几乎所有计算机都包含 C 语言编译器,因此,当你学会了 C 语言,就可以在任何环
境下进行编程。 最后一点, 掌握 C 语言可以为理解面向对象的 C++语言奠定良好的基础。
在作者眼中,有抱负的程序员必将面对三重障碍,即掌握遍布程序设计语言中的各
类术语、理解如何使用语言元素(而不仅仅只是知道它们的概念)以及领会如何在实际场
景中应用该语言。本书的目的就是将这些障碍降到最低限度。
术语是专业人士及优秀业余爱好者之间的交流必不可少的,因此有必要掌握它们。
本书将确保你理解这些术语,并自如地在各种环境下使用它们。这样才能更有效地使用
大多数软件产品附带的文档,且能轻松地阅读和学习大部分程序设计语言相关的著作。
理解语言元素的语法和作用固然是学习 C 语言过程中的一个重要部分,但认识语言
特性如何工作及应用也同等重要。本书不仅采用了代码片段,还在每个章节中使用一些
实际应用示例展示语言特性如何应用于特定的问题。这些示例提供了实践的基础,读者
可以通过改动代码观察修改后的结果。
理解特定背景下的程序设计不仅只是应用个别语言元素。为了帮助读者理解它们,
本书大部分章节之后都给出了一个较为复杂的应用程序,以应用本章之前学到的知识。
这些程序可以帮助你获得开发应用程序的能力与信心,了解如何联合以及更大范围地应
用语言元素。最重要的是,它们能让你了解设计实际应用程序与管理实际代码会碰到的
问题。
不管学习什么程序设计语言,有几件事情都要意识到。首先,虽然要学的东西很多,
但是掌握它们之后,你就会有极大的成就感。其次,学习的过程很有趣,你会深深地体
会到这点;第三,只有通过动手实践才能学会编程,这也是本书贯彻的思想。最后,在
学习的过程中,肯定会时不时犯许多错误和感到沮丧。当觉得自己完全停滞时,你要做
的就是坚持。最终你一定会体验到成功的喜悦,并且回头想想时,你会觉得它也并没有
你想象中的那么难。 如何使用本书
作者认为动手实践是学习编程最好的方法,很快你就会编写第一个程序了。每一章
都会有几个将理论应用于实践的程序,它们也是本书的核心所在。建议读者手工键入并
运行书中的示例,因为手工键入可以极大地帮助记忆语言元素。此外,你还应当尝试解
决每章末尾的所有练习题。当你第一次将一个程序运行成功,尤其是在解决自己的问题
后,你会感觉到很大的成就感和惊人的进步速度,那时你一定会觉得一切都挺值得。
刚开始,学习的进展不会太快,不过随着逐渐深入,你的学习速度会越来越快。每
一章都会涉及许多基础知识,因此在学习新的内容之前,需要花些时间确保理解前面学
习过的所有知识。实践各部分的代码,并尝试实现自己的想法,这是学习程序设计语言
的一个重要部分。尝试修改书中的程序,看看还能让它们做些什么,那才是有趣之处。
不要害怕尝试,如果某些地方不太明白,尝试输入一些变体,看看会出现什么情况。出
错并没什么大不了,你会从出错中学到很多知识。一个不错的方法是彻底通读每一章,
了解各章的范围,然后回过头来过一遍所有的示例。
你可能会觉得某些章末尾的练习题非常难。如果第一次没有完全搞明白,不用担心。
之所以第一次觉得困难是因为它们通常都是将你所学的知识应用到了相对复杂的问题
中。如果你实在觉得困难的话,可以略过它们继续学习下一章,然后再回头研究这些程
序。你甚至可以阅读完整本书再考虑它们。尽管如此,如果你能完成练习的话,说明你
取得了真正的进步。
本书读者对象
《C 语言入门经典(第 5 版)》的目的是教会读者如何尽可能简单快速地编写有用的
程序。在阅读完全书后,读者会彻底了解 C 语言编程。这本教程面向的是那些之前编过
一些程序,了解背后的概念,并且希望通过学习 C 语言进一步扩展知识的读者。尽管如
此,本书并未假设读者拥有先前的编程知识,因此如果你刚刚接触编程,本书依然是你
的不错选择。
使用本书的条件
要使用本书,你需要一台安装 C 编译器和库的计算机以执行书中的示例,以及一个
程序文本编译器用于创建源代码文件。你使用的编译器应支持目前 C 语言国际标准
(ISO/IEC 9899:2011,也被称为 C11)。你还需要一个用于创建和修改代码的编辑器,可以
采用纯文本编辑器(如记事本(Notepad)或 vi)创建源文件。不过,采用专为编辑 C 语言代
码设计的编辑器会更有帮助。
以下是作者推荐的两款 C 语言编译器,均为免费软件:
● GNU C 编译器, GCC,可从 http://www.gnu.org 下载,它支持多种不同的操作系统
环境。
● 面向 Microsoft Windows 的 Pelles C 编译器,可从 http://www.smorgasbordet.com/
pellesc/下载,它提供了一个非常棒的集成开发环境(IDE)。
本书采用的约定
本书的文本和布局采用了许多不同的样式,以便区分各种不同的信息。大多数样式
表达的含义都很明显。程序代码样式如下:
如果代码片段是从前面的实例修改而来,修改过的代码行就用粗体显示,如下所示:
i 当代码出现在文本中时,它的样式会有所不同,如: double 。
程序代码中还是用了各种“括号”。它们之间的差别非常重要,不同称呼。本书中称
()为圆括号, {}为大括号, []为方括号。
第 章 语言编程 1.1 C 语言 .........................................1
1.2 标准库.........................................2
1.3 学习 C .........................................2
1.4 创建 C 程序 ................................2
1.4.1 编辑 ........................................ 2
1.4.2 编译 ........................................ 3
1.4.3 链接 ........................................ 4
1.4.4 执行 ........................................ 4
1.5 创建第一个程序.........................5
1.6 编辑第一个程序.........................5
1.7 处理错误.....................................6
1.8 剖析一个简单的程序.................7
1.8.1 注释 ........................................ 7
1.8.2 预处理指令 ............................ 8
1.8.3 定义 main()函数..................... 9
1.8.4 关键字 .................................. 10
1.8.5 函数体 .................................. 10
1.8.6 输出信息 .............................. 11
1.8.7 参数 ...................................... 11
1.8.8 控制符 .................................. 11
1.8.9 三字母序列 .......................... 13
1.9 预处理器...................................14
1.10 用 C 语言开发程序 ................14
1.10.1 了解问题 ............................ 14
1.10.2 详细设计 ............................ 15
1.10.3 实施 .................................... 15
1.10.4 测试 .................................... 15
1.11 函数及模块化编程 .................16
1.12 常见错误.................................19
1.13 要点.........................................19
1.14 小结.........................................20
1.15 习题.........................................20
第 章 编程初步 2.1 计算机的内存 ...........................21
2.2 什么是变量 ...............................23
2.3 存储整数的变量 .......................24
2.3.1 变量的使用 .......................... 28
2.3.2 变量的初始化 ...................... 29
2.4 变量与内存 ...............................36
2.4.1 带符号的整数类型 .............. 36
2.4.2 无符号的整数类型 .............. 37
2.4.3 指定整数常量 ...................... 37
2.5 使用浮点数 ...............................39
2.6 浮点数变量 ...............................41
2.6.1 使用浮点数完成除法
运算 ...................................... 42
2.6.2 控制输出中的小数位数 ...... 43
2.6.3 控制输出的字段宽度 .......... 43
2.7 较复杂的表达式 .......................44
2.8 定义命名常量 ...........................46
2.8.1 极限值 .................................. 49
2.8.2 sizeof 运算符........................ 51
2.9 选择正确的类型 .......................52
2.10 强制类型转换 .........................55
2.10.1 自动转换类型 .................... 56
2.10.2 隐式类型转换的规则 ........ 56
2.10.3 赋值语句中的隐式类型
转换 ...................................... 57
2.11 再谈数值数据类型 .................58
2.11.1 字符类型 ............................ 58
2.11.2 字符的输入输出 ................ 59
2.11.3 枚举 .................................... 62
2.11.4 存储布尔值的变量 ............ 64
2.12 赋值操作的 op=形式..............65
2.13 数学函数 .................................66 2.14 设计一个程序.........................67
2.14.1 问题 .................................. 68
2.14.2 分析 .................................. 68
2.14.3 解决方案 .......................... 70
2.15 小结.........................................73
2.16 练习.........................................74
第 3 章 条件判断...............................75
3.1 判断过程...................................75
3.1.1 算术比较 .............................. 75
3.1.2 基本的 if 语句 ...................... 76
3.1.3 扩展 if 语句: if-else ............ 79
3.1.4 在 if 语句中使用代码块 ...... 82
3.1.5 嵌套的 if 语句 ...................... 83
3.1.6 测试字符 .............................. 85
3.1.7 逻辑运算符 .......................... 88
3.1.8 条件运算符 .......................... 91
3.1.9 运算符的优先级................... 94
3.2 多项选择问题...........................98
3.2.1 给多项选择使用 else-if
语句 ...................................... 98
3.2.2 switch 语句 ........................... 99
3.2.3 goto 语句 ........................... 107
3.3 按位运算符.............................108
3.3.1 按位运算符的 op=用法 ..... 110
3.3.2 使用按位运算符................. 111
3.4 设计程序................................. 114
3.4.1 问题 .................................... 114
3.4.2 分析 .................................... 114
3.4.3 解决方案 ............................ 114
3.5 小结......................................... 118
3.6 练习......................................... 118
第 4 章 循环.................................... 119
4.1 循环......................................... 119
4.2 递增和递减运算符.................120
4.3 for 循环 ...................................120
4.4 for 循环的一般语法 ...............124
4.5 再谈递增和递减运算符.........125
4.5.1 递增运算符 ........................ 125
4.5.2 递增运算符的前置和后置
形式 .................................... 125
4.5.3 递减运算符 ........................ 126
4.6 再论 for 循环 ..........................127
4.6.1 修改 for 循环变量.............. 129
4.6.2 没有参数的 for 循环.......... 129
4.6.3 循环内的 break 语句.......... 130
4.6.4 使用 for 循环限制输入...... 132
4.6.5 生成伪随机整数 ................ 135
4.6.6 再谈循环控制选项 ............ 137
4.6.7 浮点类型的循环控制
变量 .................................... 137
4.7 while 循环 ...............................138
4.8 嵌套循环 .................................140
4.9 嵌套循环和 goto 语句 ............146
4.10 do-while 循环........................147
4.11 continue 语句.........................149
4.12 设计程序 ...............................150
4.12.1 问题 ............................... 150
4.12.2 分析 ............................... 150
4.12.3 解决方案 ....................... 151
4.13 小结 .......................................162
4.14 习题 .......................................163
第 5 章 数组 ................................... 165
5.1 数组简介 .................................165
5.1.1 不用数组的程序 ................ 165
5.1.2 什么是数组 ........................ 167
5.1.3 使用数组 ............................ 168
5.2 寻址运算符 .............................171
5.3 数组和地址 .............................173
5.4 数组的初始化 .........................174
5.5 确定数组的大小 .....................175
5.6 多维数组 .................................176
5.7 多维数组的初始化 .................178
5.8 变长数组 .................................184
5.9 设计一个程序 .........................186
5.9.1 问题 ................................... 186
5.9.2 分析 ................................... 186
5.9.3 解决方案 ........................... 187
5.10 小结.......................................193
5.11 习题.......................................193
第 6 章 字符串和文本的应用...........195
6.1 什么是字符串.........................195
6.2 存储字符串的变量.................197
字符串数组 ................................... 199
6.3 字符串操作.............................202
6.3.1 检查对 C11 的支持 ........... 202
6.3.2 确定字符串的长度............ 203
6.3.3 复制字符串 ....................... 204
6.3.4 连接字符串 ....................... 204
6.3.5 比较字符串 ....................... 208
6.3.6 搜索字符串 ........................ 211
6.3.7 单元化字符串.................... 215
6.3.8 将换行符读入字符串........ 219
6.4 分析和转换字符串.................221
6.4.1 转换字符的大小写形式.... 223
6.4.2 将字符串转换成数值........ 225
6.5 设计一个程序.........................227
6.5.1 问题 ................................... 227
6.5.2 分析 ................................... 227
6.5.3 解决方案 ........................... 228
6.6 小结.........................................233
6.7 习题.........................................233
第 7 章 指针....................................235
7.1 指针初探.................................235
7.1.1 声明指针 ........................... 236
7.1.2 通过指针访问值................ 237
7.1.3 使用指针 ........................... 240
7.1.4 指向常量的指针................ 244
7.1.5 常量指针 ........................... 244
7.1.6 指针的命名 ....................... 245
7.2 数组和指针.............................245
7.3 多维数组.................................248
7.3.1 多维数组和指针 ................ 252
7.3.2 访问数组元素 .................... 253
7.4 内存的使用 .............................256
7.4.1 动态内存分配: malloc()
函数 .................................... 256
7.4.2 释放动态分配的内存 ........ 257
7.4.3 用 calloc()函数分配
内存 .................................... 261
7.4.4 扩展动态分配的内存 ........ 262
7.5 使用指针处理字符串 .............265
7.5.1 使用指针数组 .................... 266
7.5.2 指针和数组记号 ................ 272
7.6 设计程序 .................................276
7.6.1 问题 .................................... 276
7.6.2 分析 .................................... 277
7.6.3 解决方案 ............................ 277
7.7 小结 .........................................284
7.8 习题 .........................................285
第 8 章 编程的结构 ........................ 287
8.1 程序的结构 .............................287
8.1.1 变量的作用域和生存期 .... 288
8.1.2 变量的作用域和函数 ........ 291
8.2 函数 .........................................291
8.2.1 定义函数 ............................ 291
8.2.2 return 语句.......................... 294
8.3 按值传递机制 .........................299
8.4 函数原型 .................................300
8.5 指针用作参数和返回值 .........301
8.5.1 常量参数 ............................ 302
8.5.2 返回指针的风险 ................ 307
8.6 小结 .........................................310
8.7 习题 .........................................310
第 9 章 函数再探 ............................ 313
9.1 函数指针 .................................313
9.1.1 声明函数指针 .................... 313
9.1.2 通过函数指针调用函数 .... 314
9.1.3 函数指针的数组 ................ 316 9.1.4 作为变元的函数指针........ 319
9.2 函数中的变量.........................321
9.2.1 静态变量:函数内部
的追踪 ............................... 321
9.2.2 在函数之间共享变量........ 323
9.3 调用自己的函数:递归.........325
9.4 变元个数可变的函数.............328
9.4.1 复制 va_list........................ 331
9.4.2 长度可变的变元列表
的基本规则 ....................... 331
9.5 main()函数 ..............................332
9.6 结束程序.................................333
9.6.1 abort()函数......................... 333
9.6.2 exit()和 atexit()函数 .......... 333
9.6.3 _Exit()函数 ........................ 334
9.6.4 quick_exit()和 at_quick_exit()
函数 ................................... 334
9.7 提高性能.................................335
9.7.1 内联声明函数.................... 335
9.7.2 使用 restrict 关键字........... 335
9.7.3 _Noreturn 函数限定符 ...... 336
9.8 设计程序.................................336
9.8.1 问题 ................................... 336
9.8.2 分析 ................................... 337
9.8.3 解决方案 ........................... 338
9.9 小结.........................................351
9.10 习题.......................................352
第 10 章 基本输入和输出操作.........353
10.1 输入和输出流.......................353
10.2 标准流...................................354
10.3 键盘输入...............................354
10.3.1 格式化键盘输入 ........... 355
10.3.2 输入格式控制字符串 ... 355
10.3.3 输入格式字符串中
的字符 ........................... 360
10.3.4 输入浮点数的各种
变化 ............................... 362
10.3.5 读取十六进制和八进
制值................................ 363
10.3.6 用 scanf_s()读取字符 .... 364
10.3.7 从键盘上输入字符串 .... 366
10.3.8 单个字符的键盘输入 .... 367
10.4 屏幕输出 ...............................372
10.4.1 使用 printf_s()的格式化
输出................................ 372
10.4.2 转义序列........................ 375
10.4.3 整数输出........................ 375
10.4.4 输出浮点数.................... 378
10.4.5 字符输出........................ 379
10.5 其他输出函数 .......................380
10.5.1 屏幕的非格式化输出 .... 381
10.5.2 数组的格式化输出 ........ 381
10.5.3 数组的格式化输入 ........ 382
10.6 小结 .......................................382
10.7 习题 .......................................383
第 11 章 结构化数据....................... 385
11.1 数据结构:使用 struct..........385
11.1.1 定义结构类型和结构
变量................................ 387
11.1.2 访问结构成员 ................ 388
11.1.3 未命名的结构 ................ 390
11.1.4 结构数组 ........................ 391
11.1.5 表达式中的结构成员 .... 393
11.1.6 结构指针 ........................ 393
11.1.7 为结构动态分配内存 .... 394
11.2 再探结构成员 .......................397
11.2.1 将一个结构作为另一个
结构的成员.................... 397
11.2.2 声明结构中的结构 ........ 398
11.2.3 将结构指针用作结构
成员................................ 399
11.2.4 双向链表 ........................ 403
11.2.5 结构中的位字段 ............ 406
11.3 结构与函数 ...........................407
11.3.1 结构作为函数的变元.... 407
11.3.2 结构指针作为函数
变元 ............................... 408
11.3.3 作为函数返回值的
结构 ............................... 409
11.3.4 二叉树 ........................... 414
11.4 共享内存...............................421
11.5 设计程序...............................425
11.5.1 问题 ............................... 425
11.5.2 分析 ............................... 426
11.5.3 解决方案 ....................... 426
11.6 小结.......................................438
11.7 习题.......................................438
第 12 章 处理文件...........................441
12.1 文件的概念...........................441
12.1.1 文件中的位置 ............... 442
12.1.2 文件流 ........................... 442
12.2 文件访问...............................442
12.2.1 打开文件 ....................... 443
12.2.2 缓存文件操作 ............... 445
12.2.3 文件重命名 ................... 446
12.2.4 关闭文件 ....................... 447
12.2.5 删除文件 ....................... 447
12.3 写入文本文件.......................448
12.4 读取文本文件.......................449
12.5 在文本文件中读写
字符串 ..................................452
12.6 格式化文件的输入输出.......456
12.6.1 格式化文件输出 ........... 456
12.6.2 格式化文件输入 ........... 457
12.7 错误处理...............................459
12.8 再探文本文件操作模式.......460
12.9 freopen_s()函数 ....................461
12.10 二进制文件的输入输出.....462
12.10.1 以二进制模式打开
文件........................... 462
12.10.2 写入二进制文件 ....... 463
12.10.3 读取二进制文件........ 464
12.11 在文件中移动 .....................469
12.11.1 文件定位操作............ 469
12.11.2 找出我们在文件中
的位置........................ 470
12.11.3 在文件中设定位置.... 471
12.12 使用临时文件 .....................477
12.12.1 创建临时文件............ 477
12.12.2 创建唯一的文件名.... 478
12.13 更新二进制文件 .................479
12.13.1 修改文件的内容........ 484
12.13.2 从键盘输入创建
记录 ........................... 485
12.13.3 将记录写入文件........ 486
12.13.4 从文件中读取记录.... 486
12.13.5 写入文件.................... 487
12.13.6 列出文件内容............ 488
12.13.7 更新已有的文件
内容 ........................... 489
12.14 文件打开模式小结 .............495
12.15 设计程序 .............................496
12.15.1 问题 ........................... 496
12.15.2 分析 ........................... 496
12.15.3 解决方案.................... 496
12.16 小结 .....................................501
12.17 习题 .....................................501
第 13 章 支持功能 .......................... 503
13.1 预处理 ...................................503
13.1.1 在程序中包含头文件 .... 503
13.1.2 定义自己的头文件 ........ 504
13.1.3 管理多个源文件 ............ 504
13.1.4 外部变量........................ 505
13.1.5 静态函数........................ 505
13.1.6 替换程序源代码 ............ 506
13.2 宏 ...........................................507
13.2.1 看起来像函数的宏 ........ 507
13.2.2 字符串作为宏参数 ........ 509 13.2.3 在宏展开式中结合两个
变元 ............................... 510
13.3 多行上的预处理器指令.......510
13.3.1 预处理器逻辑指令 ........ 511
13.3.2 条件编译 ........................ 511
13.3.3 测试多个条件 ............... 512
13.3.4 取消定义的标识符 ....... 512
13.3.5 测试标识符的指定值
的指令 ........................... 512
13.3.6 多项选择 ....................... 513
13.3.7 标准预处理宏 ............... 514
13.4 调试方法...............................515
13.4.1 集成的调试器 ............... 515
13.4.2 调试阶段的预处理器 ... 515
13.4.3 断言 ............................... 519
13.5 日期和时间函数...................521
13.5.1 获取时间值 ................... 522
13.5.2 获取日期 ....................... 525
13.5.3 确定某一天是星期几 ... 529
13.6 小结.......................................531
13.7 习题.......................................531
第 14 章 高级专用主题 ...................533
14.1 使用国际字符集...................533
14.1.1 理解 Unicode................. 533
14.1.2 设置区域 ....................... 534
14.1.3 宽字符类型 wchar_t ..... 535
14.1.4 宽字符串的操作 ........... 537 14.1.5 宽字符的文件流操作 .... 540
14.1.6 存储 Unicode 字符的
固定大小类型................ 541
14.2 用于可移植性的专用整数
类型 ......................................545
14.2.1 固定宽度的整型 ............ 545
14.2.2 最小宽度的整型 ............ 545
14.2.3 最大宽度的整型 ............ 546
14.3 复数类型 ...............................546
14.3.1 复数基础........................ 546
14.3.2 复数类型和操作 ............ 547
14.4 用线程编程 ...........................550
14.4.1 创建线程........................ 550
14.4.2 退出线程........................ 551
14.4.3 把一个线程连接到另一个
线程上............................ 552
14.4.4 挂起线程........................ 555
14.4.5 管理线程对数据
的访问............................ 555
14.5 小结 .......................................561
附录 A 计算机中的数学知识........... 563
附录 B ASCII 字符代码定义 ........... 571
附录 C C 语言中的保留字 .............. 575
附录 D 输入输出格式指定符 .......... 577
附录 E 标准库头文件 ..................... 583


第 1 章
C 语言编程
C 语言是一种功能强大、简洁的计算机语言,通过它可以编写程序,指挥计算机完
成指定的任务。我们可以利用 C 语言创建程序(即一组指令),并让计算机依指令行事。
用 C 语言编程并不难, 本书将用浅显易懂的方法介绍 C 语言的基础知识, 读完本章,
读者就可以编写第一个 C 语言程序了,其实 C 语言很简单。
本章的主要内容:
● C 语言标准
● 标准库的概念
● 如何创建 C 程序
● 如何组织 C 程序
● 如何编写在屏幕上显示文本的程序
1.1 C C 是相当灵活的,用于执行计算机程序能完成的几乎所有任务,包括会计应用程序、
字处理程序、游戏、操作系统等。它不仅是更高级语言(如 C++)的基础,目前还以 Objective
C 的形式开发手机应用程序。 Objective C 是标准的 C 加上一小部分面向对象编程功能。
C 很容易学习,因为它很简洁。因此,如果你立志成为一名程序员,最好从 C 语言开始
学起,能快速而方便地获得编写实际应用程序的足够知识。
C 语言由一个国际标准定义,目前,其最新版本由 ISO/IEC 9899:2011 文档定义。当
前的标准一般称为 C11,本书介绍的语言遵循 C11 标准。但要知道, C11 定义的一些语
言元素是可选的。这表示, 遵循 C11 标准的 C 编译器可能没有实现该标准中的所有功能。
(编译器只是一个程序, 它可以把用我们能理解的术语所编写的程序转换为计算机能理解
的术语)。本书会标识出 C11 中的可选语言特性,这样读者就知道,自己的编译器可能不
支持它。
C11 编译器还有可能没有实现 C11 标准强制的所有语言特性。实现新语言功能是需
要时间的,所以编译器开发人员常常采用逐步接近的方式实现它们。这也是程序可能不
工作的另一个原因。尽管如此,根据我的经验, C 程序不能工作的最常见原因,至少有
99.9%的可能性是出现了错误。
1.2 C 的标准库也在 C11 标准中指定。标准库定义了编写 C 程序时常常需要的常量、符
号和函数。它还提供了基本 C 语言的一些可选扩展。取决于机器的特性,例如计算机的
输入输出,由标准库以不依赖机器的形式实现。这意味着,在 PC 中用 C 代码把数据写
入磁盘文件的方式,与在其他计算机上相同,尽管底层的硬件处理相当不同。库提供的
标准功能包括大多数程序员都可能需要的功能,例如处理文本字符串或数学计算,这样
就免除了自己实现这些功能所需的大量精力。
标准库在一系列标准文件——头文件中指定。头文件的扩展名总是.h。为了使一组标
准功能可用于 C 程序文件,只需要将对应的标准头文件包含进来,其方式在本章后面介
绍。我们编写的每个程序都会用到标准库。附录 E 汇总了构成标准库的头文件。
1.3 C
如果对编程非常陌生,则不需要学习 C 的某些方面,至少在刚开始时不需要学习。
这些功能比较特殊,或者不大常用。本书把它们放在第 14 章,这里读者可以在熟悉其他
内容后,再学习它们。
所有示例的代码都可以从 Apress 网站(http://www.apress/com)上下载,但建议读者自
己输入本书中的所有示例,即使它们非常简单,也要输入。自己亲自输入,以后就不容
易忘记。不要害怕用代码进行实验。犯错对编程而言非常有教育性。早期犯的错误越多,
学到的东西就越多。
1.4 C C 程序的创建过程有 4 个基本步骤或过程:
● 编辑
● 编译
● 链接
● 执行
这些过程很容易完成(就像翻转手掌一样简单,而且可以随时翻转),首先介绍每个
过程,以及它们对创建 C 程序的作用。
1.4.1 编辑
编辑过程就是创建和修改 C 程序的源代码——我们编写的程序指令称为源代码。有
些 C 编译器带一个编辑器,可帮助管理程序。通常,编辑器是提供了编写、管理、开发
与测试程序的环境,有时也称为集成开发环境(Integrated Development Environment, IDE)。
也可以用一般的文本编辑器来创建源文件,但它们必须将代码保存为纯文本,而没
有嵌入附加的格式化数据。不要使用字处理器(例如微软的 Word),字处理器不适合编写
程序代码,因为它们在保存文本时,会附加一些格式化信息。一般来说,如果编译器系
统带有编辑器,就会提供很多更便于编写及组织程序的功能。它们通常会自动编排程序
文本的格式,并将重要的语言元素以高亮颜色显示,这样不仅让程序容易阅读,还容易
找到单词输入错误。
在 Linux 上,最常用的文本编辑器是 Vim 编辑器,也可以使用 GNU Emacs 编辑器。
对于 Microsoft Windows,可以使用许多免费(freeware)或共享(shareware)的程序设计编辑
器。这些软件提供了许多功能,例如,高亮显示特殊的语法及代码自动缩进等功能,帮
助确保代码是正确的。 Emacs 编辑器也有 Microsoft Windows 版本。 UNIX 环境的 Vi 和
VIM 编辑器也可用于 Windows,甚至可以使用 Notepad++(http://notepad-plus-plus.org/)。
当然,也可以购买支持 C 语言的专业编程开发环境,例如微软或 Borland 的相关产
品,它们能大大提高代码编辑能力。不过,在付款之前,最好检查一下它们支持的 C 级
别是否符合当前的 C 语言标准 C11。因为现在很多编辑器产品主要面向 C++开发人员,
C 语言只是一个次要目标。
1.4.2 编译
编译器可以将源代码转换成机器语言,在编译的过程中,会找出并报告错误。这个
阶段的输入是在编辑期间产生的文件,常称为源文件。
编译器能找出程序中很多无效或无法识别的错误,以及结构错误,例如程序的某部
分永远不会执行。编译器的输出结果称为对象代码(object code),存放它们的文件称为对
象文件(object file),这些文件的扩展名在 Microsoft Windows 环境中通常是.obj,在
Linux/UNIX 环境中通常是.o。编译器可以在转换过程中找出几种不同类型的错误,它们
大都会阻止对象文件的创建。
如果编译成功,就会生成一个文件,它与源文件同名,但扩展名是.o 或者.obj。
如果在 UNIX 系统下工作,在命令行上编译 C 程序的标准命令是 cc(若编译器是
GNU’s Not UNIX(GNU),则命令为.gcc)。下面是一个示例:
其中, myporg.c 是要编译的程序,如果省略了–c 这个参数,程序还会自动链接。
成功编译的结果是生成一个对象文件。
大多数 C 编译器都有标准的编译选项,在命令行(如 cc myprog.c)或集成开发环境下
的菜单选项(Compile 菜单选项)里都可找到。在 IDE 中编译常常比使用命令行容易得多。
编译过程包括两个阶段。第一个阶段称为预处理阶段,在此期间会修改或添加代码,
第二个阶段是生成对象代码的实际编译过程。源文件可以包含预处理宏,它们用于添加
或修改 C 程序语句。如果现在不理解它们,不必担心,本书后面将进行详细论述。
1.4.3 链接
链接器(linker)将源代码文件中由编译器产生的各种对象模块组合起来,再从 C 语言
提供的程序库中添加必要的代码模块,将它们组合成一个可执行的文件。链接器也可以
检测和报告错误,例如,遗漏了程序的某个部分,或者引用了一个根本不存在的库组件。
实际上,如果程序太大,可将其拆成几个源代码文件,再用链接器连接起来。因为
很难一次编写一个很大的程序,也不可能只使用一个文件。如果将它拆成多个小源文件,
每个源文件提供程序的一部分功能,程序的开发就容易多了。这些源文件可以分别编译,
更容易避免简单输入错误的发生。再者,整个程序可以一点一点地开发,组成程序的源
文件通常会用同一个项目名称集成,这个项目名称用于引用整个程序。
程序库提供的例程可以执行非 C 语言的操作,从而支持和扩展了 C 语言。例如,库
中包含的例程支持输入、输出、计算平方根、比较两个字符串,或读取日期和时间信息
等操作。
链接阶段出现错误,意味着必须重新编辑源代码;反过来,如果链接成功,就会产
生一个可执行文件,但这并不一定表示程序能正常工作。在 Microsoft Windows 环境下,
这个可执行文件的扩展名为.exe;在 UNIX 环境下,没有扩展名,但它是一个可执行的
文件类型。多数 IDE 也有 Build(建立)选项,它可一次完成程序的编译和链接。
1.4.4 执行
执行阶段就是当成功完成了前述 3 个
过程后,运行程序。但是,这个阶段可能
会出现各种错误,包括输出错误及什么也
不做,甚至使计算机崩溃。不管出现哪种
情况,都必须返回编辑阶段,检查并修改
源代码。
在这个阶段,计算机最终会精确地执
行指令。在 UNIX 和 Linux 下,只要键入编
译和链接后的文件名,即可执行程序。在
大多数 IDE 中,都有一个相应的菜单命令
来运行或者执行已编译的程序。这个 Run
命令或者 Execute 命令可能有自己的菜单,
也可能位于 Compile 菜单项下。在 Windows
环境中,运行程序的.exe 文件即可,这与运
行其他可执行程序一样。
在任何环境及任何语言中,开发程序
的编辑、编译、链接与执行这 4 个步骤都
是一样的。图 1-1 总结了创建 C 程序的各
个过程。
编辑
创建/修改
程序源代码
源文件
对象文件
可执行文件
成功!
是 错误?

执行
运行程序
是 错误?

错误?
链接
链接库等
编译
生成机器指令
否 否

成都创新互联服务项目包括东源网站建设、东源网站制作、东源网页制作以及东源网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,东源网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到东源省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

C语言入门经典(第5版)

图 1-1 创建和执行程序

1.5 本节先浏览一下创建 C 语言程序的流程,从输入代码到执行程序的所有 4 个步骤。
在这个阶段,若不了解所键入的代码信息,别担心,笔者会解释每一个步骤。
试试看: 程序示例
打开编辑器,输入下面的程序,请注意标点符号不要输错,第 4 行及最后一行的括
号是大括号{},而不是方括号[]或者圆括号()——这很重要。另外一定要键入斜杠(/),以
后也会用到反斜杠(\)。最后别忘了行末的分号(;)。
在输入了上面的源代码后,将程序保存为 hello.c。可以用任意名字替代 hello,但扩
展名必须是.c。这个扩展名在编写 C 程序时是一个通用约定,它表示文件的内容是 C 语
言源代码。大多数 C 编译器都要求源文件的扩展名是.c,否则编译器会拒绝处理它。
下面编译程序(如本章前面“编译”一节所述),链接所有必要的内容,创建一个可
执行程序(如本章前面“链接”一节所述)。编译和链接一般在一个操作中完成,通常称
为“构建操作”。源代码编译成功后,链接器就添加程序需要的标准库代码,为程序创建
一个可执行文件。
最后,执行程序。这有几种方式,在 Windows 环境下,一般只需要在 Windows Explorer
中双击.exe 文件,但最好打开一个命令行窗口,输入执行它的命令,因为在程序执行完
毕后,显示输出的窗口就会消失。在所有的操作系统环境上,都可以从命令行上运行程
序。只需要启动一个命令行会话,把当前目录改为包含程序可执行文件的目录,再输入
程序名,就可以执行它了。
如果没有出现错误,就大功告成了。这个程序会在屏幕上输出如下信息:
1.6 我们可以修改程序,在屏幕上输出其他信息,例如可以将程序改成:

这个版本的输出是:
, , , 在要显示的文本中, \”序列称为转义序列(escape sequence)。文本中包含几个不同的
转义序列。 \”是在文本中包含双引号的特殊方式,因为双引号通常表示字符串的开头和
结尾。转义序列\”使双引号出现在输出的开头和结尾。如果不使用转义序列,不仅双引
号不会出现在输出中,而且程序不会编译。本章后面的“控制字符”一节将详细介绍转
义序列。
修改完源代码后,可以重新编译,链接后执行。反复练习,熟悉整个流程。
1.7 犯错乃人之常情,没什么难为情的。幸好计算机一般不会出错,而且非常擅长于找
出我们犯的错误。编译器会列出在源代码中找到的一组错误信息(甚至比我们想象的多),
通常会指出有错误的语句。此时,我们必须返回编辑阶段,找出有错误的代码并更正。
有时一个错误会使后面本来正确的语句也出现错误。这多半是程序的其他部分引用
了错误语句定义的内容所造成的。当然,定义语句有错,但被定义的内容不一定有错。
下面看看源代码在程序中生成了一个错误时,会是什么样的情况。编辑第二个程序
示例,将 printf()行最后的分号去掉,如下所示:
编译这个程序后,会看到错误信息,具体信息随编译器的不同而略有区别。下面是
一个比较常见的错误信息:
编译器能精确地指出错误及其出处,在这里, printf()行的结尾处需要一个分号。在
开始编写程序时,可能有很多错误是简单的拼写错误造成的。还很容易忘了逗号、括号,
或按错了键。没关系,许多有经验的老手也常犯这种错误。
如前所述,有时一点小错误会造成大灾难,编译器会显示许多不同的错误信息。不
要被错误的数量吓倒,仔细看过每一个错误信息后,返回并改掉错误部分,不懂的先不
管它,然后再编译一次源文件,就会发现错误一次比一次少。
返回编辑器,重新输入分号,再编译,看看有没有其他错误,如果没有错误,程序
就可以执行了。
1.8 编写并编译了第一个程序后,下面是另一个非常类似的例子,了解各行代码的作用:

这和第一个程序完全相同,这里把它作为练习,用编辑器输入这个示例,编译并执
行。若输入完全正确,会看到如下输出:
1.8.1 注释
上述示例的第一行代码如下:
这不是程序代码,因为它没有告诉电脑执行操作,它只是一个注释,告诉阅读代码
的人,这个程序要做什么。位于/*和*/之间的任意文本都是注释。只要编译器在源文件中
找到/*,就忽略它后面的内容(即使其中的文本很像程序代码),一直到表示注释结束的*/
为止。 /*可以和*/放在同一行代码上,也可以放在不同的代码行上。如果忘记包含对应的
*/,编译器就会忽略/*后面的所有内容。下面使用一个注释说明代码的作者及版权所有:
也可以修饰注释,使它们比较突出:
使用另一种记号,可以在代码行的末尾添加一个注释,如下所示:
代码行上两个斜杠后面的所有内容都会被编译器忽略。这种形式的注释没有前一种
记号那么凌乱,尤其是在注释只占一行的情形下。
应养成给程序添加注释的习惯,当然程序也可以没有注释,但在编写较长的程序时,
可能会忘记这个程序的作用或工作方式。添加足够的注释,可确保日后自己(和其他程序
员)能理解程序的作用和工作方式。
下面给程序再添加一些注释:
可以看出,使用注释是一种非常有效的方式,可以解释程序中要发生的事情。注释
可以放在程序中的任意位置,说明代码的一般作用,指定代码是如何工作的。
1.8.2 预处理指令
下面的代码行:

严格说来,它不是可执行程序的一部分,但它很重要,事实上程序没有它是不执行
的。符号#表示这是一个预处理指令(preprocessing directive),告诉编译器在编译源代码之
前,要先执行一些操作。编译器在编译过程开始之前的预处理阶段处理这些指令。预处
理指令相当多,大多放于程序源文件的开头。
在这个例子中,编译器要将 stdio.h 文件的内容包含进来,这个文件称为头文件(header
file),因为它通常放在程序的开头处。在本例中,头文件定义了 C 标准库中一些函数的
信息,但一般情况下,头文件指定的信息应由编译器用于在程序中集成预定义函数或其
他全局对象,所以有时需要创建自己的头文件,以用于程序。本例要用到标准库中的
printf()函数,所以必须包含 stdio.h 头文件。 stdio.h 头文件包含了编译器理解 printf()以及
其他输入/输出函数所需要的信息。名称 stdio 是标准输入/输出(standard input/output)的缩
写。 C 语言中所有头文件的扩展名都是.h,本书的后面会用到其他头文件。
注意:
在一些系统中,头文件名是不区分大小写的,但在#include 指令里,这些文件名通
常是小写。
每个符合 C11 标准的 C 编译器都有一些标准的头文件。这些头文件主要包含了与 C
标准库函数相关的声明。所有符合该标准的 C 编译器都支持同一组标准库函数,有同一

分享标题:C语言入门经典(第5版)
网站网址:http://cdxtjz.cn/article/jcohde.html

其他资讯