第1章 关键字 1
1.1 最宽宏大量的关键字——auto 3
1.2 最快的关键字——register 3
1.2.1 皇帝身边的小太监——寄存器 3
1.2.2 使用register修饰符的注意点 4
1.3 最名不符实的关键字——static 4
1.3.1 修饰变量 4
1.3.2 修饰函数 5
1.4 基本数据类型——short、int、long、char、float、double 5
1.4.1 数据类型与“模子” 6
1.4.2 变量的命名规则 6
1.5 最冤枉的关键字——sizeof 12
1.5.1 常年被人误认为函数 12
1.5.2 sizeof(int)*p表示什么意思 13
1.6 signed、unsigned关键字 13
1.7 if、else组合 17
1.7.1 bool变量与“零值”进行比较 17
1.7.2 float变量与“零值”进行比较 18
1.7.3 指针变量与“零值”进行比较 19
1.7.4 else到底与哪个if配对呢 20
1.7.5 if语句后面的分号 21
1.7.6 使用if语句的其他注意事项 22
1.8 switch、case组合 23
1.8.1 不要拿青龙偃月刀去削苹果 23
1.8.2 case关键字后面的值有什么要求吗 24
1.8.3 case语句的排列顺序 25
1.8.4 使用case语句的其他注意事项 26
1.9 do、while、for关键字 27
1.9.1 break与continue的区别 28
1.9.2 循环语句的注意点 30
1.10 goto关键字 31
1.11 void关键字 32
1.11.1 void a 32
1.11.2 void修饰函数返回值和参数 33
1.11.3 void指针 34
1.11.4 void不能代表一个真实的变量 35
1.12 return关键字 36
1.13 const关键字也许该被替换为readonly 36
1.13.1 const修饰的只读变量 37
1.13.2 节省空间,避免不必要的内存分配,同时提高效率 37
1.13.3 修饰一般变量 38
1.13.4 修饰数组 38
1.13.5 修饰指针 38
1.13.6 修饰函数的参数 38
1.13.7 修饰函数的返回值 38
1.14 最易变的关键字——volatile 39
1.15 最会带帽子的关键字——extern 40
1.16 struct关键字 41
1.16.1 空结构体多大 41
1.16.2 柔性数组 42
1.16.3 struct与class的区别 43
1.17 union关键字 44
1.17.1 大小端模式对union类型数据的影响 44
1.17.2 如何用程序确认当前系统的存储模式 45
1.18 enum关键字 49
1.18.1 枚举类型的使用方法 49
1.18.2 枚举与#define宏的区别 51
1.19 伟大的缝纫师——typedef关键字 51
1.19.1 关于马甲的笑话 51
1.19.2 历史的误会——也许应该是typerename 51
1.19.3 typedef与#define的区别 53
1.19.4 #define a int[10]与typedef int a[10] 53
第2章 符号 56
2.1 注释符号 57
2.1.1 几个似非而是的注释问题 57
2.1.2 y=x/*p 58
2.1.3 怎样才能写出出色的注释 58
2.2 接续符和转义符 62
2.3 单引号、双引号 63
2.4 逻辑运算符 63
2.5 位运算符 64
2.5.1 左移和右移 66
2.5.2 0x01<<2+3的值为多少 66
2.6 花括号 66
2.7 ++、——操作符 67
2.7.1 ++i+++i+++i 68
2.7.2 贪心法 68
2.8 2/(-2)的值是多少 69
2.9 运算符的优先级 70
2.9.1 运算符的优先级表 70
2.9.2 一些容易出错的优先级问题 72
第3章 预处理 73
3.1 宏定义 74
3.1.1 数值宏常量 74
3.1.2 字符串宏常量 75
3.1.3 用define宏定义注释符号“?” 75
3.1.4 用define宏定义表达式 75
3.1.5 宏定义中的空格 78
3.1.6 #undef 79
3.2 条件编译 80
3.3 文件包含 82
3.4 #error预处理 82
3.5 #line预处理 83
3.6 #pragma预处理 83
3.6.1 #pragma message 84
3.6.2 #pragma code_seg 84
3.6.3 #pragma once 84
3.6.4 #pragma hdrstop 84
3.6.5 #pragma resource 85
3.6.6 #pragma warning 85
3.6.7 #pragma comment 86
3.6.8 #pragma pack 86
3.7 “#”运算符 90
3.8 “##”预算符 91
第4章 指针和数组 92
4.1 指针 92
4.1.1 指针的内存布局 92
4.1.2 “*”与防盗门的钥匙 93
4.1.3 int*p=NULL和*p=NULL有什么区别 94
4.1.4 如何将数值存储到指定的内存地址 95
4.1.5 编译器的bug 95
4.1.6 如何达到手中无剑、胸中也无剑的境界 97
4.2 数组 97
4.2.1 数组的内存布局 97
4.2.2 省政府和市政府的区别——&a[0]和&a的区别 99
4.2.3 数组名a作为左值和右值的区别 99
4.3 指针和数组之间的恩恩怨怨 100
4.3.1 以指针的形式访问和以下标的形式访问 100
4.3.2 a和&a的区别 101
4.3.3 指针和数组的定义与声明 103
4.3.4 指针和数组的对比 106
4.4 指针数组和数组指针 106
4.4.1 指针数组和数组指针的内存布局 106
4.4.2 int(*)[10]p2——也许应该这么定义数组指针 107
4.4.3 再论a和&a之间的区别 108
4.4.4 地址的强制转换 109
4.5 多维数组和多级指针 111
4.5.1 二维数组 111
4.5.2 二级指针 114
4.6 数组参数和指针参数 115
4.6.1 一维数组参数 115
4.6.2 一级指针参数 118
4.6.3 二维数组参数和二级指针参数 120
4.7 函数指针 121
4.7.1 函数指针的定义 121
4.7.2 函数指针的使用 121
4.7.3 (*(void(*)())0)()——这是什么 123
4.7.4 函数指针数组 124
4.7.5 函数指针数组指针 125
第5章 内存管理 127
5.1 什么是野指针 127
5.2 栈、堆和静态区 128
5.3 常见的内存错误及对策 128
5.3.1 指针没有指向一块合法的内存 128
5.3.2 为指针分配的内存太小 130
5.3.3 内存分配成功,但并未初始化 130
5.3.4 内存越界 131
5.3.5 内存泄漏 132
5.3.6 内存已经被释放了,但是继续通过指针来使用 135
第6章 函数 136
6.1 函数的由来与好处 136
6.2 编码风格 137
6.3 函数设计的一般原则和技巧 143
6.4 函数递归 152
6.4.1 一个简单但易出错的递归例子 152
6.4.2 不使用任何变量编写strlen函数 153
第7章 文件结构 155
7.1 文件内容的一般规则 155
7.2 文件名命名的规则 160
7.3 文件目录的规则 160
第8章 关于面试的秘密 161
8.1 外表形象 161
8.1.1 学生就是学生,穿着符合自己身份就行了 161
8.1.2 不要一身异味,熏晕考官对你没好处 162
8.1.3 女生不要带2个以上耳环,不要涂指甲 162
8.2 内在表现 163
8.2.1 谈吐要符合自己身份,切忌不懂装懂、满嘴胡咧咧 163
8.2.2 态度是一种习惯,习惯决定一切 163
8.2.3 要学会尊敬别人和懂礼貌 165
8.3 如何写一份让考官眼前一亮的简历 166
8.3.1 个人信息怎么写 167
8.3.2 求职意向和个人的技能、获奖或荣誉情况怎么突出 168
8.3.3 成绩表是应届生必须要准备的 170
附录1 C语言基础测试题 171
附录2 C语言基础测试题答案 177
后记 180
参考文献 182