内容简介
本书讲解了栈、堆、指针、文件等各类编程概念和数据结构及其应用,通过对比编程中的常见错误与正确的程序之间的区别来提高读者的编程技能,介绍如何成为程序员的经验和技巧。尤其是本书将离散数学中的相关概念与程序设计紧密相连,细致地阐述递归程序的思想、实现和应用,使读者能够从中习得更多知识,掌握高级编程技巧。本书可作为高等院校C语言相关课程的本科生教材,也可作为中等编程水平的学生提升编程技能的参考书。
作者简介
Yung-Hsiang Lu(陆永祥),现为普度大学电子和计算机工程学院副教授。他是ACM杰出科学家和杰出讲者, IEEE重启计算计划(Rebooting Computing initiative)成员。他还是2015年首届低功耗图像识别竞赛的主要组织者,IEEE多媒体通信技术委员会的多媒体通信系统兴趣组的主席(2014-2016)。他2002年获得了斯坦福大学电子工程系博士学位。
目录
Intermediate C Programming
出版者的话
译者序
序
前言
第一部分 计算机存储:内存和文件
第1章 程序的执行 2
1.1 编译 2
1.2 重定向输出 6
第2章 栈内存 7
2.1 值和地址 7
2.2 栈 8
2.3 调用栈 9
2.3.1 返回位置 9
2.3.2 函数实参 12
2.3.3 局部变量 14
2.3.4 值地址 15
2.3.5 数组 16
2.3.6 获取地址 17
2.4 可见度 17
2.5 习题 20
2.5.1 绘制调用栈I 20
2.5.2 绘制调用栈II 20
2.5.3 地址 21
2.6 习题解答 21
2.6.1 绘制调用栈I 21
2.6.2 绘制调用栈II 22
2.6.3 地址 22
2.7 在DDD(命令行调试程序)上检测调用栈 22
第3章 预防、检测及消除bug 26
3.1 开发软件≠编码 26
3.1.1 编程前 26
3.1.2 编程中 27
3.1.3 编程后 28
3.2 常见错误 28
3.2.1 未初始化变量 28
3.2.2 错误数组下标 28
3.2.3 错误数据类型 28
3.3 后执行式和交互式调试 28
3.4 生产代码与测试代码分离 29
第4章 指针 30
4.1 作用域 30
4.2 swap函数 31
4.3 指针 33
4.4 再论swap函数 37
4.5 类型错误 39
4.6 数组和指针 40
4.7 类型规则 43
4.8 指针运算 44
4.9 习题 47
4.9.1 swap函数1 47
4.9.2 swap函数2 48
4.9.3 swap函数3 48
4.9.4 swap函数4 48
4.9.5 swap函数5 49
4.9.6 15 552种变化 49
4.10 习题解答 50
4.10.1 swap函数1 50
4.10.2 swap函数2 50
4.10.3 swap函数3 51
4.10.4 swap函数4 51
4.10.5 swap函数5 51
第5章 编写和测试程序 52
5.1 不同的数组元素 52
5.1.1 main函数 52
5.1.2 areDistinct函数 53
5.1.3 编译和链接 54
5.1.4 make工具 55
5.2 使用Makefile测试 57
5.2.1 生成测试用例 58
5.2.2 重定向输出 58
5.2.3 使用diff去比较输出 58
5.2.4 添加测试到Makefile 59
5.3 无效的内存访问 60
5.4 使用valgrind检查内存访问错误 62
5.5 测试覆盖 64
5.6 限制内核大小 67
5.7 带有死循环的程序 67
第6章 字符串 69
6.1 字符数组 69
6.2 C语言中的字符串函数 72
6.2.1 复制函数:strcpy 72
6.2.2 比较函数:strcmp 73
6.2.3 寻找子字符串函数:strstr 73
6.2.4 寻找字符函数:strchr 74
6.3 理解argv 74
6.4 对子字符串计数 77
第7章 编程问题和调试 80
7.1 实现字符串函数 80
7.1.1 C语言库 80
7.1.2 头文件 80
7.1.3 mystring.h 82
7.1.4 创建输入和正确输出 82
7.1.5 Makefile 86
7.1.6 mystring.c 86
7.1.7 使用const 88
7.2 调试 89
7.2.1 找到死循环 90
7.2.2 找到无效内存访问 91
7.2.3 检测无效内存访问 92
第8章 堆内存 94
8.1 用malloc函数创建数组 94
8.2 栈和堆 96
8.3 返回堆地址的函数 98
8.4 C语言中的二维数组 99
8.5 指针和参数 101
第9章 使用堆内存的编程问题 104
9.1 对数组排序 104
9.1.1 生成测试输入和期望输出 104
9.1.2 重定向输入 105
9.1.3 整数排序 107
9.1.4 使用valgrind检测内存泄漏 110
9.2 使用qsort进行排序 111
9.2.1 qsort 111
9.2.2 比较函数 112
9.2.3 执行范例 114
9.2.4 对字符串排序 115
第10章 读写文件 118
10.1 通过argv传递一个文件名 118
10.2 读取文件 119
10.2.1 读取字符型:fgetc 119
10.2.2 读取整型:fscanf(...%d...) 121
10.3 写入文件 123
10.4 读写字符串 125
第11章 编程解决使用文件的问题 128
11.1 对文件中的整数进行排序 128
11.2 计算字符出现的次数 130
11.3 计算单词出现的次数 132
11.4 如何注释程序 134
第二部分 递归
第12章 递归 138
12.1 在限制条件下选取小球 138
12.1.1 双色球问题 138
12.1.2 三色球问题 139
12.1.3 附加限制条件 140
12.2 单行道 142
12.3 汉诺塔 143
12.4 计算整数分拆 145
12.4.1 计算“1”的个数 147
12.4.2 仅使用奇数进行分拆 148
12.4.3 使用递增数进行分拆 148
12.4.4 交替使用奇偶数进行分拆 149
12.4.5 整数分拆问题的推广 151
12.4.6 解决分拆问题的错误方法 151
第13章 递归函数 152
13.1 在限制条件下选取小球 152
13.2 单行道 155
13.3 汉诺塔 156
13.4 整数分拆 158
13.5 阶乘 159
13.6 斐波那契数列 161
13.7 利用gprof进行性能分析 165
第14章 整数分拆 167
14.1 堆内存和栈内存 168
14.2 追踪递归函数调用 176
14.3 约束条件下的分拆 178
14.3.1 仅使用奇数进行分拆 179
14.3.2 使用递增数进行分拆 179
14.3.3 交替使用奇偶数进行分拆 180
14.3.4 使用gprof和gcov查找性能瓶颈 180
第15章 使用递归解决问题 187
15.1 二分搜索 187
15.2 快速排序 189
15.3 排列组合 195
前言/序言
Intermediate C Programming为什么要写这本书市面上有成百上千种关于编程的书籍,其中有很多都是关于C语言编程的,那么为什么我还要写这本书呢?为什么建议你花时间读它呢?这本书跟其他书有什么不同呢?跟很多作者一样,我写这本书是因为我觉得有必要,觉得这本书中的方法比其他书中的更好。
我将现在已有的关于编程的书分为两类:入门和进阶。入门类书是给初学者写的,一般都假设读者没有编程基础,所以主要是介绍基本的概念。通常以“Hello World!”程序开始,也就是将“Hello World!”输出到电脑屏幕的程序。这种类型的书主要是一步步地介绍语言特点,包括关键词、数据类型、控制结构、字符串、文件操作等,而这些书一般都有一个特点:程序很短,一般是1~2页。这很奏效,因为短程序有助于解释编程语言的新概念。如果把学编程语言比作学自然语言,如英语、汉语、法语、韩语等,这些书就相当于教导如何造句和撰写短段落。
第二类书是写给有程序开发经验的读者的。这些书主要介绍解决现实中的问题的程序,比如关于电脑游戏或者图像。而这类书的例子一般很长,有些甚至几千行代码,因此不会全部印在书本上。书中只会解释程序的其中一部分,而源程序一般保存在CD或者某个网址上。这类书一般不会再介绍如何编程,而是大多专注于解决特定问题的算法研究,有时包括算法性能的详细信息。读者不可能再找到类似于“Hello World!”这样的例子。再比作自然语言的例子,这类书就是在教导如何撰写可能超过20页的短篇小说。
问题是,从写一个段落到写一篇小说,这种跨越太难了。
一本针对中级编程能力的学生的书市面上很少有针对中级编程能力学生的书籍。这些学生往往已经掌握了编程的基本知识,在看到if或者while时不会茫然,知道如何创建函数和调用函数,有能力编写几十上百行的短代码,却不知道如何处理上千行的程序。他们经常会犯错误,因为大多数入门级的书籍只教导如何编写正确的程序,却不会教导避免常见的错误。他们往往对大多数的概念和那些可以帮助提高编程能力的工具都不太熟悉,他们需要这样一个台阶:可以帮助他们从有能力编写短代码到有能力编写解决现实问题的程序。
现在入门和进阶的空档已经被数据结构和算法的书籍填充了一部分,这类图书一般提供实现数据结构或算法的完整例子。然而这并不是最合适的解决方法,这类图书致力于介绍数据结构和算法,却罕有提供帮助读者编写正确代码的信息。事实上,它们大多只提供程序,而很少解释。它们往往不解释编程概念,比如函数需要一个指针作为实参的原因或者深拷贝与浅拷贝之间的差异等。因此,读者只能自学这些编程技巧。
为了迎合这个需求,我写下这本针对中级编程能力的学生的书,本书适合作为学习编程的第二本教材。
避免出错和调试的重点我们可以看到有很多关于如何编程的书籍,却很少关于开发软件的书籍。开发软件不是简单地输入代码,它需要更多的知识和技能。为了弥补这种不足,最好就是去研究什么是对的、什么是错的。只解释如何编写正确的程序是不够的,还需要解释常见的错误并将它们与正确的程序进行对比。
一次疏忽可能使程序运行出乎意料,甚至是某些情况下运行正确而另一些情况下出错。这种类型的错误往往很难发现,更别说更正了。本书将介绍一些常见的错误以教导读者如何避免这些错误。调试过程在大多数书中都不会涉及,罕有书籍会提到“调试器”这个词,以至于有些读者都不知道这类工具的存在。学会如何使用调试器一般不超过30分钟,这可以帮助程序员节省很多时间。关于如何使用调试器和调试策略的书籍则更少了。
程序设计和离散数学程序设计和离散数学是计算机科学中的两个重要学科,然而,大多数书籍都将这两个主题分开,所以很少会在编程的书籍中看到数学公式,同样也很难在离散数学中看到代码。在本书中,这两个主题紧密结合,我相信读者可以从中学到更多的知识。
为什么本书使用C语言?C语言诞生于20世纪60年代后期和20世纪70年代早期。在C语言发明之后,很多语言也相继出现,这些语言也深受C语言的影响。除了它的历史影响之外,C语言的简单易用也保证了它在几乎所有现代化平台中的重要地位。与许多操作系统一样,Linux是就用C语言编写的,Android基本都是用Java编写的但仍有叫作JNI(Java Native Interface,Java本地接口)的C语言接口。大多数计算机语言都可以与C语言进行通信或通过C语言进行通信,事实上这对一种编程语言而言是有用的,因为大多数操作系统接口都使用C语言。当一个全新的系统被设计出来,C语言通常是第一种(很多情况下是唯一一种)被系统支持的编程语言。
……
C语言程序设计进阶教程 电子书 下载 mobi epub pdf txt