在C语言的学习过程中,初学者往往因为不熟悉各种语法规范导致各种错误,进阶学习者常常希望编制出更高效、更有质量的程序。如何解决不同读者的学习需求?本书作者创新性地提出了从“错误”这个角度入手的方案,通过列举初学者容易遇到的典型问题,对比分析正确和错误的程序,来帮助读者更好地掌握C语言编程技术;通过演示如何将一个能运行的程序优化为更好、更可靠的程序,帮助读者建立好的编程风格,提高编程质量。
《C语言解惑》特点:
在结构上,本书分为两篇:第一篇是C语言编程中的对与错,主要是分析编程中存在的典型错误、对比正确与错误的方法;第二篇是对比质量好与质量差的程序,继续采用第一篇分析对与错的方法,但主要是针对能运行而编程质量不好的程序,寻找质量“好”的替代质量“差”的,从而提高实用编程能力。两篇内容难度逐步递增,使读者循序渐进地获得进步。
在内容上,结合作者的教学和工程实践,安排了大量正反两方面的实例,通过比较对错和优劣,使读者留下深刻的印象,更容易记住编程的要诀,并进一步建立好的编程风格,最终提高编程能力和程序的质量。
在写法上,作者采用深入浅出、诙谐幽默的语言,使枯燥的语法内容变得生动有趣,既能激发读者的学习兴趣,又能让读者轻松记住相应的知识。本书不仅能为初学者打开启蒙之路,又能为编程者指出进修之路,因此,既适合作为C语言的教材,也可作为程序员的编程手册。
前言
第一篇 C语言编程中的对与错
第1章 初涉C语言者的困惑
1.1 中文字符以假乱真
1.2 象形字体扰乱视听
1.3 都是注释惹的祸
1.4 千万不要忘记我
1.5 别把分号放错地方
1.6 少了花括号就是行不通
1.7 scanf要"&"不要"\n"
1.8 老大就是要在最前面
1.9 记住我就会受益无穷
第2章 用好printf和scanf一对活宝
2.1 printf输出的小奥妙
2.2 printf输出整数或字符
2.3 输入的格式配对错误
2.4 空格让scanf莫名其妙
2.5 回车键打乱scanf的阵脚
2.6 字符输入要搞特殊化
2.7 别混淆字符数组和字符
2.8 一维数组更要特殊对待
2.9 输出值的操作符
2.10 引入指针更方便
2.11 指针的困惑
第3章 基本数据类型
3.1 混合运算要小心
3.2 数据类型的后缀符号
3.3 基本数据的初始化
3.4 注意编译系统的差别
3.5 不要用错等于运算符
3.6 不要用错逗号运算符
第4章 程序控制语句
4.1 控制流程运算容易出现的问题
4.1.1 写错关系运算符
4.1.2 混淆表达式和关系表达式的值
4.1.3 混淆逻辑表达式和逻辑表达式的值
4.1.4 混淆逻辑运算符和位运算符
4.2 程序控制语句容易出现的问题
4.2.1 条件分支语句的错误
4.2.2 控制重复的分支语句
4.2.3 运算符优先级错误
4.2.4 求值顺序
第5章 数组与指针是重点
5.1 一维数组越界和初始化错误
5.1.1 一维数组越界错误
5.1.2 一维数组初始化错误
5.2 数组赋值错误
5.3 指针地址的有效性
5.4 配合使用一维数组与指针
5.4.1 使用一维数组名简化操作
5.4.2 使用指针操作一维数组
5.4.3 使用一维字符数组
5.4.4 不要忘记指针初始化
5.5 多维数组与指针
5.5.1 数组操作及越界和初始化错误
5.5.2 二维数组与指针
5.5.3 二维数组与指向一维数组的指针
第6章 函数是核心
6.1 函数的声明与定义
6.2 函数变量的作用域
6.3 函数变量类型的匹配
6.4 函数的返回路径
6.5 函数参数的设计及传递
6.6 传递指针不一定改变原来参数的值
6.7 函数的返回值
6.7.1 无返回值的void类型函数
6.7.2 函数返回值问题
第7章 宏与const
7.1 用const代替无参数的宏定义
7.2 有参数的宏定义
第8章 库函数
8.1 引用的库函数与头文件不匹配
8.2 与库函数的参数类型不匹配
8.3 对库函数的作用理解不对
8.4 充分利用库函数printf的功能
8.4.1 printf的函数原型
8.4.2 printf函数的格式控制符
第9章 结构
9.1 结构定义和赋值错误
9.2 结构作为函数参数及函数的返回值
9.3 使用结构数组和指针容易出现的错误
9.4 其他注意事项
第10章 联合与枚举
10.1 联合
10.2 枚举
第11章 状态机
第二篇 C语言编程中的好与坏
第12章 注意编译系统的差别
12.1 打开所有编译开关
12.2 克服依靠编译系统产生的错误
第13章 测试与调试程序
13.1 预防措施
13.1.1 书写格式和注意事项
13.1.2 命名注意事项
13.1.3 程序注释
13.2 使用条件编译
13.3 消灭警告信息
13.4 使用简单的输出信息调试程序
13.5 编写error函数
13.6 使用集成环境提供的调试手段
13.6.1 一个简单的实例
13.6.2 编译程序
13.6.3 排错
13.6.4 基本调试命令简介
13.6.5 程序与汇编调试窗口
13.7 调试程序实例
13.8 软件测试
13.8.1 模块测试
13.8.2 组装测试
13.8.3 确认测试
13.9 程序的测试与调试
13.10 测试用例设计技术
13.10.1 逻辑覆盖法
13.10.2 等价划分法
13.10.3 边值分析法
13.10.4 因果图法
13.10.5 错误猜测法
第14章 正确使用变量、常量和指针
14.1 基本数据类型的变量初始化
14.2 不要混淆字符和字符串
14.3 指针的初始化
14.4 指针相等
14.5 使用const
14.5.1 左值和右值
14.5.2 推荐使用const定义常量
14.5.3 对函数传递参数使用const限定符
14.5.4 对指针使用const限定符
14.6 使用volatile变量
14.7 变量的存储地址分配
第15章 正确使用宏
15.1 不要使用不存在的运算符
15.2 正确使用定义的宏
15.3 正确定义宏的参数
15.4 使用宏定义函数
第16章 控制语句
16.1 运算顺序错误
16.2 采用更明确的条件
16.3 设计存在的问题
16.3.1 没有涵盖全部条件
16.3.2 条件超出范围
16.3.3 减少循环次数
16.4 正确选择运算符
16.5 优先级和求值顺序错误
第17章 位运算
17.1 位运算典型错误
17.2 位运算典型实例
第18章 再论数组与指针
18.1 一维数值数组和指针
18.1.1 使用数组偏移量造成数组越界
18.1.2 使用数组名进行错误运算
18.1.3 错误使用数组下标和指向数组指针的下标
18.1.4 小结
18.2 一维字符数组和指针
18.2.1 字符数组的偏移量
18.2.2 字符数组不对称编程综合实例
18.3 动态内存
18.3.1 非数组的指针
18.3.2 NULL指针
18.4 二维数组和指针
18.4.1 二维数组的界限
18.4.2 二维数组的一维特性
18.4.3 指向二维数组的指针
18.5 数组和指针应用实例
第19章 再论函数
19.1 函数变量的作用域
19.1.1 块结构之间的变量屏蔽规则
19.1.2 程序和文件内的变量
19.1.3 多文件变量作用域
19.2 函数的参数
19.2.1 完璧归赵
19.2.2 多余的参数
19.2.3 传递的参数与函数参数
匹配问题
19.2.4 等效替换参数
19.3 函数的类型和返回值
19.3.1 函数的类型力求简单
19.3.2 实参要与函数形参的类型匹配
19.3.3 正确设计函数的返回方式
19.3.4 正确设计和使用函数指针
19.3.5 如何解读函数声明
第20章 再论库函数
20.1 getchar函数的返回类型不是字符
20.2 setbuf函数与其他函数的配合
20.3 错误使用errno函数
20.4 模拟设计printf函数
20.4.1 具有可变参数的函数
20.4.2 设计简单的打印函数
20.4.3 利用宏改进打印函数
20.5 scanf和sscanf函数
20.5.1 sscanf函数的使用方法
20.5.2 sscanf函数用法举例
20.6 探讨printf函数
第21章 再论结构
21.1 同类型结构变量之间的整体赋值
21.2 使用键盘赋值
21.2.1 为结构变量赋值
21.2.2 为结构指针变量赋值
21.2.3 为链表赋值
21.2.4 为结构数组的变量赋值
21.2.5 为含有指针域的结构数组赋值
21.3 使用结构作为函数的参数
21.3.1 结构变量的传数值与传地址值
21.3.2 结构数组传地址值
21.4 结构函数的返回值
21.5 修改传递的结构参数的值
21.6 优先使用结构指针传递参数
第22章 使用文件常见错误分析
22.1 文件的打开与关闭
22.2 文件的读写
22.3 其他读写函数
22.4 文件的定位
22.5 操作出错检测及错误标志的复位
22.6 文件的内存分配
22.7 小结
第23章 多文件编程
23.1 多文件编程错误浅析
23.2 单文件结构
23.3 一个源文件和一个头文件
23.4 多文件结构
第24章 发布C程序
24.1 两种版本的异同
24.2 两种版本的设置
第25章 典型问题
25.1 计算机解题具有多解的特点
25.2 应对算法进行优化
25.3 优化时要避免出现新的错误
25.4 扩展程序要注意是否满足全部条件
25.5 注意函数设计的多样化和效率
25.6 使用多文件编程
25.7 使用状态机设计程序
附录A C语言操作符的优先级
附录B 简化优先级记忆口诀
附录C 7位ASCII代码表
主要参考文献