我竭尽全力地推荐这本我所见过的最好的C编程入门图书。作者深知读者所需,并为他们打下良好基础。如果你已经开始学习C语言但始终不得要领,不妨试一试这本书。 ——Francis Glassborow, ACCU主席 本书提供与C语言编程相关的全面资源和深入讨论。本书通过对指针的基础知识和高级特性的探讨,帮助程序员把指针的强大功能融入到自己的程序中去。 全书共18章,覆盖了数据、语句、操作符和表达式、指针、函数、数组、字符串、结构和联合等几乎所有重要的C编程话题。书中给出了很多编程技巧和提示,每章后面有针对性很强的练习,附录部分则给出了部分练习的解答。 本书适合C语言初学者和初级C程序员阅读,也可作为计算机专业学生学习C语言的参考。
第1章 快速上手 \r\n1.1 简介 \r\n1.1.1 空白和注释 \r\n1.1.2 预处理指令 \r\n1.1.3 main函数 \r\n1.1.4 read_column_numbers函数 \r\n1.1.5 rearrange函数 \r\n1.2 补充说明 \r\n1.3 编译 \r\n1.4 总结 \r\n1.5 警告的总结 \r\n1.6 编程提示的总结\r\n1.7 问题 \r\n1.8 编程练习 \r\n第2章 基本概念 \r\n2.1 环境 \r\n2.1.1 翻译 \r\n2.1.2 执行 \r\n2.2 词法规则 \r\n2.2.1 字符 \r\n2.2.2 注释 \r\n2.2.3 自由形式的源代码 \r\n2.2.4 标识符 \r\n2.2.5 程序的形式 \r\n2.3 程序风格\r\n2.4 总结 \r\n2.5 警告的总结\r\n2.6 编程提示的总结 \r\n2.7 问题 \r\n2.8 编程练习 \r\n第3章 数据\r\n3.1 基本数据类型 \r\n3.1.1 整型家族 \r\n3.1.2 浮点类型 \r\n3.1.3 指针 \r\n3.2 基本声明 \r\n3.2.1 初始化 \r\n3.2.2 声明简单数组 \r\n3.2.3 声明指针 \r\n3.2.4 隐式声明 \r\n3.3 typedef \r\n3.4 常量 \r\n3.5 作用域\r\n3.5.1 代码块作用域 \r\n3.5.2 文件作用域 \r\n3.5.3 原型作用域 \r\n3.5.4 函数作用域 \r\n3.6 链接属性 \r\n3.7 存储类型 \r\n3.8 static关键字\r\n3.9 作用域、存储类型示例 \r\n3.10 总结 \r\n3.11 警告的总结 \r\n3.12 编程提示的总结 \r\n3.13 问题 \r\n第4章 语句 \r\n4.1 空语句 \r\n4.2 表达式语句 \r\n4.3 代码块\r\n4.4 if语句 \r\n4.5 while语句 \r\n4.5.1 break和continue语句 \r\n4.5.2 while语句的执行过程 \r\n4.6 for语句 \r\n4.7 do语句 \r\n4.8 switch语句 \r\n4.8.1 switch中的 break语句 \r\n4.8.2 default子句\r\n4.8.3 switch语句的执行过程 \r\n4.9 goto语句 \r\n4.10 总结 \r\n4.11 警告的总结 \r\n4.12 编程提示的总结\r\n4.13 问题\r\n4.14 编程练习 \r\n第5章 操作符和表达式\r\n5.1 操作符\r\n5.1.1 算术操作符 \r\n5.1.2 移位操作符 \r\n5.1.3 位操作符 \r\n5.1.4 赋值 \r\n5.1.5 单目操作符 \r\n5.1.6 关系操作符 \r\n5.1.7 逻辑操作符 \r\n5.1.8 条件操作符\r\n5.1.9 逗号操作符\r\n5.1.10 下标引用、函数调用和结构成员 \r\n5.2 布尔值 \r\n5.3 左值和右值 \r\n5.4 表达式求值 \r\n5.4.1 隐式类型转换 \r\n5.4.2 算术转换 \r\n5.4.3 操作符的属性 \r\n5.4.4 优先级和求值的顺序\r\n5.5 总结 \r\n5.6 警告的总结 \r\n5.7 编程提示的总结\r\n5.8 问题\r\n5.9 编程练习 \r\n第6章 指针 \r\n6.1 内存和地址\r\n6.2 值和类型 \r\n6.3 指针变量的内容 \r\n6.4 间接访问操作符\r\n6.5 未初始化和非法的指针 \r\n6.6 NULL指针\r\n6.7 指针、间接访问和左值 \r\n6.8 指针、间接访问和变量\r\n6.9 指针常量 \r\n6.10 指针的指针 \r\n6.11 指针表达式 \r\n6.12 实例 \r\n6.13 指针运算\r\n6.13.1 算术运算\r\n6.13.2 关系运算 \r\n6.14 总结\r\n6.15 警告的总结\r\n6.16 编程提示的总结 \r\n6.17 问题 \r\n6.18 编程练习 \r\n第7章 函数 \r\n7.1 函数定义 \r\n7.2 函数声明\r\n7.2.1 原型\r\n7.2.2 函数的缺省认定\r\n7.3 函数的参数\r\n7.4 ADT和黑盒 \r\n7.5 递归 \r\n7.5.1 追踪递归函数\r\n7.5.2 递归与迭代\r\n7.6 可变参数列表 \r\n7.6.1 stdarg宏 \r\n7.6.2 可变参数的限制 \r\n7.7 总结\r\n7.8 警告的总结\r\n7.9 编程提示的总结 \r\n7.10 问题 \r\n7.11 编程练习 \r\n第8章 数组\r\n8.1 一维数组 \r\n8.1.1 数组名\r\n8.1.2 下标引用\r\n8.1.3 指针与下标 \r\n8.1.4 指针的效率 \r\n8.1.5 数组和指针 \r\n8.1.6 作为函数参数的数组名\r\n8.1.7 声明数组参数 \r\n8.1.8 初始化 \r\n8.1.9 不完整的初始化 \r\n8.1.10 自动计算数组长度 \r\n8.1.11 字符数组的初始化 \r\n8.2 多维数组 \r\n8.2.1 存储顺序 \r\n8.2.2 数组名 \r\n8.2.3 下标 \r\n8.2.4 指向数组的指针\r\n8.2.5 作为函数参数的多维数组\r\n8.2.6 初始化 \r\n8.2.7 数组长度自动计算 \r\n8.3 指针数组 \r\n8.4 总结\r\n8.5 警告的总结 \r\n8.6 编程提示的总结 \r\n8.7 问题\r\n8.8 编程练习 \r\n第9章 字符串、字符和字节 \r\n9.1 字符串基础\r\n9.2 字符串长度 \r\n9.3 不受限制的字符串函数 \r\n9.3.1 复制字符串\r\n9.3.2 连接字符串 \r\n9.3.3 函数的返回值 \r\n9.3.4 字符串比较 \r\n9.4 长度受限的字符串函数\r\n9.5 字符串查找基础\r\n9.5.1 查找一个字符\r\n9.5.2 查找任何几个字符\r\n9.5.3 查找一个子串 \r\n9.6 高级字符串查找 \r\n9.6.1 查找一个字符串前缀 \r\n9.6.2 查找标记\r\n9.7 错误信息 \r\n9.8 字符操作 \r\n9.8.1 字符分类 \r\n9.8.2 字符转换 \r\n9.9 内存操作 \r\n9.10 总结 \r\n9.11 警告的总结 \r\n9.12 编程提示的总结\r\n9.13 问题 \r\n9.14 编程练习 \r\n第10章 结构和联合 \r\n10.1 结构基础知识 \r\n10.1.1 结构声明 \r\n10.1.2 结构成员 \r\n10.1.3 结构成员的直接访问\r\n10.1.4 结构成员的间接访问 \r\n10.1.5 结构的自引用 \r\n10.1.6 不完整的声明\r\n10.1.7 结构的初始化 \r\n10.2 结构、指针和成员 \r\n10.2.1 访问指针 \r\n10.2.2 访问结构 \r\n10.2.3 访问结构成员\r\n10.2.4 访问嵌套的结构 \r\n10.2.5 访问指针成员 \r\n10.3 结构的存储分配 \r\n10.4 作为函数参数的结构\r\n10.5 位段 \r\n10.6 联合 \r\n10.6.1 变体记录\r\n10.6.2 联合的初始化 \r\n10.7 总结 \r\n10.8 警告的总结\r\n10.9 编程提示的总结 \r\n10.10 问题 \r\n10.11 编程练习 \r\n第11章 动态内存分配\r\n11.1 为什么使用动态内存分配\r\n11.2 malloc和free\r\n11.3 calloc和realloc \r\n11.4 使用动态分配的内存\r\n11.5 常见的动态内存错误 \r\n11.6 内存分配实例 \r\n11.7 总结 \r\n11.8 警告的总结 \r\n11.9 编程提示的总结\r\n11.10 问题 \r\n11.11 编程练习 \r\n第12章 使用结构和指针\r\n12.1 链表\r\n12.2 单链表 \r\n12.2.1 在单链表中插入\r\n12.2.2 其他链表操作 \r\n12.3 双链表\r\n12.3.1 在双链表中插入 \r\n12.3.2 其他链表操作\r\n12.4 总结\r\n12.5 警告的总结 \r\n12.6 编程提示的总结\r\n12.7 问题 \r\n12.8 编程练习 \r\n第13章 高级指针话题 \r\n13.1 进一步探讨指向指针的指针\r\n13.2 高级声明\r\n13.3 函数指针 \r\n13.3.1 回调函数\r\n13.3.2 转移表 \r\n13.4 命令行参数\r\n13.4.1 传递命令行参数\r\n13.4.2 处理命令行参数 \r\n13.5 字符串常量\r\n13.6 总结 \r\n13.7 警告的总结\r\n13.8 编程提示的总结 \r\n13.9 问题\r\n13.10 编程练习 \r\n第14章 预处理器 \r\n14.1 预定义符号 \r\n14.2 #define\r\n14.2.1 宏 \r\n14.2.2 #define替换 \r\n14.2.3 宏与函数\r\n14.2.4 带副作用的宏参数\r\n14.2.5 命名约定 \r\n14.2.6 #undef \r\n14.2.7 命令行定义\r\n14.3 条件编译 \r\n14.3.1 是否被定义\r\n14.3.2 嵌套指令 \r\n14.4 文件包含 \r\n14.4.1 函数库文件包含 \r\n14.4.2 本地文件包含 \r\n14.4.3 嵌套文件包含 \r\n14.5 其他指令 \r\n14.6 总结 \r\n14.7 警告的总结\r\n14.8 编程提示的总结 \r\n14.9 问题 \r\n14.10 编程练习 \r\n第15章 输入/输出函数 \r\n15.1 错误报告 \r\n15.2 终止执行 \r\n15.3 标准I/O函数库\r\n15.4 ANSI I/O概念 \r\n15.4.1 流 \r\n15.4.2 文件 \r\n15.4.3 标准I/O常量 \r\n15.5 流I/O总览 \r\n15.6 打开流 \r\n15.7 关闭流\r\n15.8 字符I/O\r\n15.8.1 字符I/O宏 \r\n15.8.2 撤消字符I/O\r\n15.9 未格式化的行I/O \r\n15.10 格式化的行I/O \r\n15.10.1 scanf家族\r\n15.10.2 scanf格式代码 \r\n15.10.3 printf家族\r\n15.10.4 printf格式代码\r\n15.11 二进制I/O\r\n15.12 刷新和定位函数 \r\n15.13 改变缓冲方式\r\n15.14 流错误函数 \r\n15.15 临时文件\r\n15.16 文件操纵函数\r\n15.17 总结 \r\n15.18 警告的总结 \r\n15.19 编程提示的总结\r\n15.20 问题\r\n15.21 编程练习\r\n第16章 标准函数库 \r\n16.1 整型函数 \r\n16.1.1 算术 \r\n16.1.2 随机数 \r\n16.1.3 字符串转换\r\n16.2 浮点型函数 \r\n16.2.1 三角函数 \r\n16.2.2 双曲函数\r\n16.2.3 对数和指数函数\r\n16.2.4 浮点表示形式 \r\n16.2.5 幂 \r\n16.2.6 底数、顶数、绝对值和余数 \r\n16.2.7 字符串转换\r\n16.3 日期和时间函数 \r\n16.3.1 处理器时间 \r\n16.3.2 当天时间 \r\n16.4 非本地跳转\r\n16.4.1 实例 \r\n16.4.2 何时使用非本地跳转 \r\n16.5 信号 \r\n16.5.1 信号名 \r\n16.5.2 处理信号 \r\n16.5.3 信号处理函数 \r\n16.6 打印可变参数列表 \r\n16.7 执行环境 \r\n16.7.1 终止执行 \r\n16.7.2 断言 \r\n16.7.3 环境 \r\n16.7.4 执行系统命令\r\n16.7.5 排序和查找 \r\n16.8 locale \r\n16.8.1 数值和货币格式 \r\n16.8.2 字符串和locale \r\n16.8.3 改变locale的效果 \r\n16.9 总结 \r\n16.10 警告的总结 \r\n16.11 编程提示的总结 \r\n16.12 问题\r\n16.13 编程练习 \r\n第17章 经典抽象数据类型 \r\n17.1 内存分配\r\n17.2 堆栈 \r\n17.2.1 堆栈接口\r\n17.2.2 实现堆栈 \r\n17.3 队列 \r\n17.3.1 队列接口 \r\n17.3.2 实现队列\r\n17.4 树 \r\n17.4.1 在二叉搜索树中插入 \r\n17.4.2 从二叉搜索树删除节点 \r\n17.4.3 在二叉搜索树中查找 \r\n17.4.4 树的遍历 \r\n17.4.5 二叉搜索树接口 \r\n17.4.6 实现二叉搜索树\r\n17.5 实现的改进 \r\n17.5.1 拥有超过一个的堆栈 \r\n17.5.2 拥有超过一种的类型 \r\n17.5.3 名字冲突\r\n17.5.4 标准函数库的ADT \r\n17.6 总结 \r\n17.7 警告的总结 \r\n17.8 编程提示的总结 \r\n17.9 问题 \r\n17.10 编程练习 \r\n第18章 运行时环境\r\n18.1 判断运行时环境\r\n18.1.1 测试程序\r\n18.1.2 静态变量和初始化 \r\n18.1.3 堆栈帧 \r\n18.1.4 寄存器变量\r\n18.1.5 外部标识符的长度 \r\n18.1.6 判断堆栈帧布局 \r\n18.1.7 表达式的副作用 \r\n18.2 C和汇编语言的接口 \r\n18.3 运行时效率 \r\n18.4 总结 \r\n18.5 警告的总结 \r\n18.6 编程提示的总结 \r\n18.7 问题 \r\n18.8 编程练习 \r\n附录 部分问题答案 \r\n索引 \r\n参考文献
为什么需要这本书
市面上已经有了许多优秀的讲述C语言的书籍, 为什么我们还需要这一本呢?我在大学里教授C语言编程已有10个年头, 但至今尚未发现一本书是按照我所喜欢的方式来讲述指针的. 许多书籍用一章的篇幅专门讲述指针, 而且往往出现在全书的后半部分. 但是, 仅仅描述指针的语法. 并用一些简单的例子展示其用法是远远不够的. 我在授课时, 很早便开始讲授指针, 而且在以后的授课过程中也经常讨论指针. 我描述它们在各种不同的上下文环境中的有效用法, 展示使用指针的编程惯用法(programming idiom). 我还讨论了一些相关的课题如编程效率和程序可维护性之间的权衡. 指针是本书的线索所在, 融会贯通于全书之中.
指针为什么如此重要?我的信念是:正是指针使C威力无穷. 有些任务用其他语言也可以实现, 但C能够更有效地实现, 有些任务无法用其他语言实现, 如直接访问硬件, 但C却可以. 要想成为一名优秀的C程序员, 对指针有一个深入而完整的理解是先决条件.
然而, 指针虽然很强大, 与之相伴的风险却也不小. 跟指甲锉相比, 链锯可以更快地切割木材, 但链锯更容易使你受伤, 而且伤害常常来得极快, 后果也非常严重. 指针就像链锯一样, 如果使用得当, 它们可以简化算法的实现, 并使其更富效率, 如果使用不当, 它们就会引起错误, 导致细微而令人困惑的症状, 并且极难发现原因. 对指针只是略知一二便放手使用是件非常危险的事. 如果那样的话, 它给你带来的总是痛苦而不是欢乐. 本书提供了你所需要的深入而完整的关于指针的知识, 足以使你避开指针可能带来的痛苦.
为什么要学习C语言
为什么C语言依然如此流行?历史上, 由于种种原因, 业界选择了C, 其中最主要的原因就在于它的效率. 优秀C程序的效率几乎和汇编语言程序一样高, 但C程序明显比汇编语言程序更易于开发. 和许多其他语言相比, C给予程序员更多的控制权, 如控制数据的存储位置和初始化过程等. C缺乏“安全网”特性, 这虽有助于提高它的效率, 但也增加了出错的可能性. 例如, C对数组下标引用和指针访问并不进行有效性检查, 这可以节省时间, 但你在使用这些特性时就必须特别小心. 如果你在使用C语言时能够严格遵守相关规定, 就可以避免这些潜在的问题.
C提供了丰富的操作符集合, 它们可以让程序员有效地执行一些底层的计算如移位和屏蔽等, 而不必求助汇编语言. C的这个特点使很多人把C称为“高层”的汇编语言. 但是, 当需要的时候, C程序可以很方便地提供汇编语言的接口. 这些特性使C成为实现操作系统和嵌入性控制器软件的良好选择.
C流行的另一个原因是由于它的普遍存在. C编译器在许多机器上实现. 另外, ANSI标准提高了C程序在不同机器之间的可移植性.
最后, C是C++的基础. C++提供了一种和C不同的程序设计和实现的观点. 然而, 如果你对C的知识和技巧, 如指针和标准库等成竹在胸, 将非常有助于你成为一名优秀的C++程序员.
为什么应该阅读这本书
本书并不是一本关于编程的入门图书. 它所面向的读者应该已经具备了一些编程经验, 或者是一些想学习C, 但又不想被诸如为什么循环很重要以及何时需要使用if语句等肤浅问题耽误进程的人.
另一方面, 我并不要求本书的读者以前学习过C. 我讲述了C语言所有方面的内容. 这种内容的广泛覆盖性使本书不仅适用于学生, 也适用于专业人员. 也就是说, 适用于首次学习C的读者和那些经验更丰富的希望进一步提高语言使用技巧的用户.
优秀的C++书籍把精力集中于与面向对象模型有关的课题上(如类的设计)而不是专注于基本的C技巧, 这样做是对的. 但C++是建立在C的基础之上的, C的基本技巧依然非常重要, 特别是那些能够实现可复用类的技巧. 诚然, C++程序员在阅读本书时可以跳过一些他们所熟悉的内容, 但他们会在本书中找到许多有用的C工具和技巧.
本书的组织形式
本书按照教程的形式组织, 它所面向的读者是先前具有编程经验的人. 它的编写风格类似于导师在你的身后注视着你的工作, 不时给你一些提示和忠告. 我的目标是把通常需要多年实践才能获得的知识和观点传授给读者. 这种组织形式也影响到材料的顺序——我通常在一个地方引入一个话题, 并进行完整的讲解. 因此, 本书也可以当作参考手册.
在这种组织形式中, 存在两个显著的例外之处. 首先是指针, 它贯穿全书, 将在许多不同的上下文环境中进行讨论. 其次就是第1章, 它对语言的基础知识提供了一个快速的介绍. 这种介绍有助于你很快掌握编写简单程序的技巧. 第1章所涉及的主题将在后续章节中深入讲解.
较之其他书籍, 本书在许多领域着墨更多, 主要是为了让每个主题更具深度, 向读者传授通常只有实践才能获得的经验. 另外, 我使用了一些在现实编程中不太常见的例子, 虽然有些不太容易理解, 但这些例子显示了C在某些方面的趣味所在.
ANSI C
本书描述ANSI C, 是由ANSI/ISO 9899-1990[ANSI 90]进行定义并由[KERN 89]进行描述的. 我之所以选择这个版本的C是基于两个原因:首先, 它是旧式C(有时称作Kernighan和Ritchie[KERN 78], 或称K&R C)的后继者, 并已在根本上取代了后者, 其次, ANSI C是C++的基础. 本书中的所有例子都是用ANSI C编写的. 我常常把“ANSI C标准文档”简称为“标准”.
排版说明
语法描述格式如下
if( expression )
statement
else
statement
我在语法描述中使用了4种字体, 其中必须的代码(如此例中的关键字if)将如上所示设置为Courier New字体. 必要代码的抽象描述(如上例中的expression)用Courier New表示. 有些语句具有可选部分, 如果我决定使用可选部分(如此例中的else关键字), 它将严格按上面的例子以粗体Courier New表示. 可选部分的抽象描述(如第二个statement)将以粗斜体Courier New表示. 每次引入新术语时, 我将以黑体表示.
完整的程序将标上号码, 以“程序0.1”这样的格式显示. 标题给出了程序的名称, 包含源代码的文件名则显示在右下角——这些文件都可以从Addison Wesley Longman的网站上找到.
文中有“提示”部分. 这些提示中的许多内容都是对良好编程技巧的讨论——就是使程序更易编写. 更易阅读并在以后更易理解. 当一个程序初次写成时, 稍微多做些努力就可能节约以后修改程序的大量时间. 其他一些提示能帮助你把代码写得更加紧凑或更有效率.
另外还有一些提示涉及软件工程的话题. C的诞生远早于现代软件工程原则的形成. 因此, 有些语言特性和通用技巧不为这些原则所提倡. 这些话题通常涉及到某种特定结构的效率和代码的可读性和可维护性之间的利弊权衡. 这方面的讨论将向你提供一些背景知识, 帮助你判断效率上的收益是否抵得上其他质量上的损失.
当你看到“警告”时就要特别小心:我将要指出的是C程序员新手(有时甚至是老手)经常出现的错误之一, 或者代码将不会如你所预想的那样运行. 这个警告标志将使提示内容不易被忘记, 而且以后回过头来寻找也更容易一些.
“K&R C”表示我正在讨论ANSI C和K&R C之间的重要区别. 尽管绝大多数以K&R C写成的程序仅需极微小的修改即可在ANSI C环境运行, 但有时你仍可能碰到一个ANSI之前的编译器, 或者遇到一个更老式的程序. 如此一来, 两者的区别便至关重要.
每章问题和编程练习
本书每章的最后一节是问题和编程练习. 问题难简不一, 从简单的语法问题到更为复杂的问题诸如效率和可维护性之间的权衡等. 编程练习按等级区分难度:( 的练习最为简单, ((((( 的练习难度最大. 这些练习有许多作为课堂测验已沿用多年. 问题或编程练习前如果有一个 符号, 表示在附录中可以找到它的参考答案.
补充材料
Addison Wesley Longman专门为本书维护了一个World Wide Web站点. 该站点的URL是http://www.awl.com/cseng/titles/0-673-99986-6/(或可直接访问作者主页www.cs.rit.edu/~kar/). 这个站点包含本书所有程序的源代码, 以章为单位分类. 你还可以在上面看到本书的最新勘误表. 你还可以联系附近的Addison Wesley Longman代表, 获取Instructor's Guide, 它包含了书上未给出答案的问题和编程练习的所有答案.
如果你是一位教育工作者, 也可以免费获取UNIX系统上自动递交和测试学生程序的软件[REEK 89, REEK 96], 通过匿名FTP:ftp.cs.rit.edu, 目录是pub/kar/try.
致谢
我无法列出所有对本书做出贡献的人们, 但我将感谢他们中的所有人. 我的妻子Margaret对我的写作鼓励有加, 为我提供精神上的支持, 而且她默默承受着由于我写作本书而带给她的生活上的孤独.
我要感谢Warren Caithers教授, 他是我在RIT的同事, 阅读并审校了本书的初稿. 他真诚的批评帮助我从一大堆讲课稿和例子中生成了一份清晰. 连贯的手稿.
我非常感谢我的C语言编程课程的学生们, 他们帮助我发现录入错误, 提出改进意见, 并在教学过程中忍受着草稿形式的教材. 你们对我的作品的反应向我提供了有益的反馈, 帮助我进一步改进本书的质量.
我还要感谢Steve Allan, Bill Appelbe, Richard C.Detmer, Roger Eggen, Joanne Goldenberg, Dan Hinton, Dan Hirschberg, Keith E.Jolly, Joseph F.Kent, Masoud Milani, Steve Summit和Kanupriya Tewary, 他们在本书出版前对它作了评价. 他们的建议和观点对我进一步改进本书的表达形式助益颇多.
最后, 我要向我在Addison-Wesley的编辑Deborah Lafferty女士. 产品编辑Amy Willcutt女士表示感谢. 正是由于她们的帮助, 才使这本书从一本书手稿成为一本正式的书籍. 她们不仅给了我很多有价值的建议, 而且鼓励我改进我原先自我感觉良好的排版. 现在我已经看到了结果, 她们的意见是正确的.
现在是开始学习的时候了, 我预祝大家在学习C语言的过程中找到快乐!
Kenneth A. Reek
kar@cs.rit.edu
Churchville, 纽约