本书将C语言中的知识由浅入深地安排成五个部分进行讲解,通过大量简明易懂的范例来演示C语言中的概念。第1部分介绍与C语言的语法及程序结构有关的基础概念。第2部分介绍C语言的数据类型。第3部分讲解如何用各种方式分配及释放内存。第4部分介绍与读取数据(输入数据)及写入数据(输出数据)有关的各种话题。第5部分详细解释如何创建并管理含有多份文件的程序项目。
译者序
前言
作者简介
审校者简介
第一部分 C语言的基础知识
第1章 运行Hello, World!程序2
1.1 技术要求2
1.2 编写第一个C语言程序3
1.3 了解程序开发流程4
1.3.1 编辑5
1.3.2 编译6
1.3.3 运行9
1.3.4 验证10
1.3.5 重复10
1.4 创建、录入并保存第一个C语言程序12
1.5 编译第一个C语言程序13
1.6 运行第一个C语言程序14
1.7 添加注释14
1.7.1 怎样写好注释15
1.7.2 给Hello, world!程序添加注释17
1.8 学着在代码上做实验18
1.9 小结19
第2章 了解程序的结构21
2.1 技术要求21
2.2 语句与代码块22
2.2.1 在语句与代码块中试验各种转义序列23
2.2.2 了解分隔符的用法25
2.2.3 了解空白的用法27
2.2.4 了解C语言的各种语句30
2.3 了解C语言的函数32
2.4 了解如何定义函数32
2.4.1 了解函数的标识符33
2.4.2 了解函数的语句块35
2.4.3 了解函数的返回值35
2.4.4 通过函数的参数传递数值37
2.5 执行顺序42
2.6 了解如何声明函数43
2.7 小结46
第3章 基本的数据类型47
3.1 技术要求47
3.2 了解数据类型48
3.3 字节与数据块51
3.4 如何在C语言代码中表示整数52
3.4.1 如何在C语言代码中表示正整数与负整数53
3.4.2 如何在C语言代码中采用大小不同的数据块来表示整数53
3.5 如何在C语言中表示小数55
3.6 如何在C语言中表示单个字符55
3.7 如何在C语言中表示布尔值56
3.8 如何在C语言中查询各种数据类型的大小57
3.8.1 sizeof()运算符57
3.8.2 各种数据类型的取值范围59
3.9 小结60
第4章 使用变量并为变量赋值61
4.1 技术要求62
4.2 选用合适的类型来表示数据值62
4.3 学习变量的用法62
4.3.1 给变量命名63
4.3.2 显式地指定变量类型64
4.3.3 显式地指定变量类型并初始化65
4.4 学习常量的用法66
4.4.1 字面常量66
4.4.2 用预处理指令定义常量值68
4.4.3 显式地定义某种类型的常量69
4.4.4 给常量命名69
4.5 把类型适当的值赋给变量70
4.5.1 通过赋值语句显式地赋值71
4.5.2 通过给函数传递参数来赋值71
4.5.3 通过return语句来赋值73
4.6 小结74
第5章 运算符与表达式75
5.1 技术要求76
5.2 表达式与运算符76
5.3 在数字值上执行运算78
5.4 类型转换83
5.4.1 隐式类型转换83
5.4.2 显式类型转换87
5.5 字符型数据支持的操作88
5.6 逻辑运算符与关系运算符89
5.7 位运算符92
5.8 条件运算符94
5.9 序列运算符95
5.10 复合赋值运算符96
5.11 在一条表达式中给多个变量赋值97
5.12 增量运算符97
5.13 运算符之间的优先次序以及括号的用法99
5.14 小结100
第6章 用条件语句控制程序流102
6.1 技术要求103
6.2 了解各种条件表达式103
6.3 if() ... else ...语句104
6.4 switch() ...语句107
6.5 多个if() ... else ...语句111
6.6 嵌套的if() ... else ...语句114
6.7 小结117
第7章 循环与迭代119
7.1 技术要求119
7.2 重复执行代码120
7.3 蛮力法实现重复执行代码122
7.4 while () ...循环语句124
7.5 for() ...循环语句127
7.6 do ... while()循环语句129
7.7 如何把一种循环改写成另一种循环131
7.8 善用goto语句以实现无条件跳转132
7.9 用break与continue语句来控制循环136
7.10 无限循环139
7.11 小结140
第8章 创建并使用枚举值141
8.1 技术要求141
8.2 枚举值142
8.2.1 定义枚举类型与枚举值143
8.2.2 使用枚举值145
8.3 用switch()...语句判断枚举变量的取值148
8.4 小结152
第二部分 复杂的数据类型
第9章 创建并使用结构体154
9.1 技术要求155
9.2 结构体155
9.2.1 声明结构体156
9.2.2 初始化结构体并访问其中的字段160
9.3 用函数操作结构体161
9.4 包含其他结构体的结构体163
9.4.1 用函数初始化结构体165
9.4.2 复用某个函数以打印大结构体中的多个小结构体166
9.5 从结构体入手理解面向对象编程169
9.6 小结170
第10章 用typedef创建自定义数据类型171
10.1 技术要求171
10.2 用typedef给固有类型起别名172
10.3 用typedef简化枚举类型的用法174
10.4 用typedef简化结构体类型的用法176
10.5 typedef的其他用法179
10.6 几个有用的编译器选项179
10.7 把自定义类型及typedef说明符放在头文件中180
10.8 小结183
第11章 数组185
11.1 技术要求185
11.2 声明并初始化数组186
11.3 访问数组中的元素189
11.4 通过循环来操作数组192
11.5 使用函数来操作数组193
11.6 小结196
第12章 多维数组198
12.1 技术要求198
12.2 从一维数组到多维数组199
12.2.1 重新审视一维数组199
12.2.2 由一维数组来理解二维数组200
12.2.3 由二维数组来理解三维数组201
12.2.4 理解N维数组203
12.3 声明并初始化多维数组203
12.3.1 声明二维数组204
12.3.2 初始化二维数组204
12.3.3 声明三维数组204
12.3.4 初始化三维数组205
12.3.5 声明并初始化N维数组205
12.4 访问多维数组中的元素206
12.5 用多层循环操作多维数组207
12.5.1 用二层的嵌套循环遍历二维数组208
12.5.2 用三层的嵌套循环遍历三维数组208
12.6 在函数中使用多维数组209
12.7 小结212
第13章 指针213
13.1 技术要求214
13.2 C语言中的难点:指针214
13.3 指针的基础知识215
13.3.1 直接寻址与间接寻址216
13.3.2 内存与内存寻址216
13.3.3 管理并访问内存217
13.3.4 用现实示例来类比指针218
13.4 指针型变量的声明、命名及赋值220
13.4.1 声明指针型变量220
13.4.2 命名指针型变量221
13.4.3 给指针赋值(让指针指向某个地址)222
13.5 与指针有关的操作222
13.5.1 给指针赋值222
13.5.2 NULL指针与void*指针223
13.5.3 访问指针的目标225
13.5.4 指针算术228
13.5.5 比较指针228
13.6 表述指针的操作230
13.7 可变函数参数231
13.7.1 按引用传递233
13.7.2 直接把地址传给函数,而不通过指针变量235
13.7.3 指向指针的指针236
13.8 指向结构体的指针238
13.8.1 通过指针访问结构体及其字段239
13.8.2 在函数中使用指向结构体的指针239
13.9 小结241
第14章 数组与指针242
14.1 技术要求242
14.2 数组名称与指针之间的关系242
14.3 数组元素与指针之间的关系245
14.4 通过指针操作数组246
14.4.1 在指针上执行算术运算246
14.4.2 对指针使用自增运算符247
14.4.3 将数组作为重新访问的函数指针传递250
14.4.4 数组名称与指向该数组的指针有时可以互换251
14.5 指向数组的指针数组253
14.6 小结259
第15章 字符串260
15.1 技术要求261
15.2 字符串的基本单元:字符261
15.2.1 char类型与ASCII字符集262
15.2.2 比ASCII更大的字符集:UTF-8及Unicode265
15.2.3 字符支持的操作266
15.2.4 判断字符是否具备某项特征268
15.2.5 操作字符270
15.3 C语言字符串275
15.3.1 带有终结符的字符数组275
15.3.2 C语言字符串的优点276
15.3.3 C语言字符串的缺点276
15.4 声明并初始化字符串277
15.4.1 声明字符串277
15.4.2 初始化字符串278
15.4.3 把字符串传给函数280
15.4.4 空白字符串与空字符串281
15.4.5 重新审视Hello, World!程序282
15.5 创建并使用字符串数组283
15.6 用标准库中的函数执行常见的字符串操作288
15.6.1 常用的字符串函数288
15.6.2 更安全的字符串函数289
15.7 小结291
第16章 创建并使用复杂的结构体293
16.1 技术要求294
16.2 为什么需要复杂的结构体294
16.3 重新审视card4.c295
16.4 理解结构体数组302
16.4.1 创建结构体数组302
16.4.2 访问数组中的结构体元素303
16.4.3 操作结构体数组305
16.5 包含小结构体的大结构体310
16.5.1 创建包含小结构体的大结构体310
16.5.2 访问大结构体中的小结构体所具备的字段311
16.5.3 操作包含小结构体的大结构体312
16.6 使用含有数组的结构体319
16.6.1 了解随机与随机数生成器319
16.6.2 创建含有数组的结构体320
16.6.3 访问结构体所含数组中的元素321
16.6.4 操作结构体所含数组中的元素321
16.7 使用含有结构体数组的大结构体324
16.7.1 创建包含结构体数组的大结构体325
16.7.2 访问大结构体中的结构体数组内的各个小结构体325
16.7.3 操作包含结构体数组的大结构体326
16.7.4 写出最终版的carddeck.c文件327
16.8 小结333
第三部分 内存分配
第17章 理解内存分配与生命期336
17.1 技术要求336
17.2 定义C语言中的各种存储类337
17.3 固定存储类(主要是其中的自动存储类)与动态存储类337
17.3.1 固定存储类(主要是其中的自动存储类)338
17.3.2 动态存储类338
17.4 内部存储类与外部存储类338
17.4.1 内部(或局部)存储类339
17.4.2 外部(或全局)存储类340
17.4.3 自动变量(即存储类为auto的变量)所具备的生命期341
17.5 理解静态变量(即存储类为static的变量)341
17.5.1 函数内的静态变量341
17.5.2 函数外的静态变量343
17.5.3 静态变量的生命期344
17.6 小结344
第18章 动态内存分配345
18.1 技术要求345
18.2 了解动态内存346
18.3 分配并释放动态内存347
18.3.1 分配动态内存348
18.3.2 释放动态内存349
18.3.3 访问动态内存350
18.3.4 动态内存的生命期350
18.4 与动态内存分配有关的注意事项351
18.5 一种动态的数据结构:链表354
18.5.1 定义链表所需的各种结构体354
18.5.2 声明链表支持的操作355
18.5.3 更复杂的链表操作364
18.5.4 编写测试程序以验证链表实现得是否正确365
18.6 其他动态数据结构369
18.7 小结370
第四部分 输入与输出
第19章 学习各种输出格式372
19.1 技术要求373
19.2 重新审视printf()函数373
19.3 用格式说明符调整无符号整数的格式375
19.3.1 在各种进制下解读无符号整数375
19.3.2 把负数当成无符号整数来显示376
19.3.3 用各种进制表示2与9的整数次方377
19.3.4 打印指针的值377
19.4 用格式说明符调整带符号整数的格式379
19.4.1 使用字段宽度、精度、对齐方式与填充方式来显示带符号整数379
19.4.2 针对长长整数指定格式说明符380
19.4.3 用各种修饰符调整2与9的整数次方的显示效果380
19.5 用格式说明符调整浮点数的格式381
19.5.1 使用字段宽度、精度、对齐方式与填充方式来显示浮点数382
19.5.2 用十六进制显示浮点数383
19.5.3 用最合适的字段宽度显示浮点数383
19.6 用格式说明符调整字符串与字符的格式385
19.6.1 使用字段宽度、精度、对齐方式与填充方式来显示字符串385
19.6.2 输出子字符串386
19.6.3 调整单个字符的输出格式386
19.7 小结387
第20章 从命令行界面获取输入信息388
20.1 技术要求388
20.2 重新审视main()函数388
20.2.1 main()函数的特别之处389
20.2.2 main()函数的两种形式389
20.3 使用argc与argv参数390
20.3.1 演示argc与argv的简单用法390
20.3.2 命令行选项与命令行处理器392
20.4 小结395
第21章 调整输入值的格式397
21.1 技术要求398
21.2 流简介398
21.2.1 理解标准输出流400
21.2.2 理解标准输入流402
21.2.3 通过printf()与fprintf()重新审视控制台输出402
21.2.4 通过scanf()函数探索控制台输入403
21.3 用scanf()函数读取格式化的输入数据404
21.3.1 用scanf()函数读取用户输入的数字值404
21.3.2 用scanf()函数读取用户输入的字符串与字符408
21.3.3 用scan set限定用户输入的字符411
21.3.4 控制scanf()处理输入数据时所用的字段宽度413
21.4 通过字符串缓冲区转换数据416
21.4.1 通过sprintf()与sscanf()在值与字符串之间转换417
21.4.2 用atoi()与atod()将字符串转换成数字418
21.5 无格式的输入与输出419
21.5.1 从控制台输入字符串或把字符串输出到控制台419
21.5.2 通过gets()函数获取简单的输入字符串并通过puts()函数显示简单的输出字符串420
21.5.3 用fgets()与fputs()获取一系列名称并输出排序后的名单421
21.6 小结425
第22章 文件427
22.1 技术要求428
22.2 文件的基本概念428
22.2.1 重新审视文件流428
22.2.2 FILE流的各项属性429
22.2.3 开启和关闭文件430
22.2.4 了解每种数据流所支持的文件操作431
22.3 文件系统的基础知识432
22.4 打开文件以读取数据或写入数据434
22.4.1 在程序中获取用户输入的文件名436
22.4.2 获取用户通过命令行参数传入的文件名438
22.5 小结439
第23章 文件输入和文件输出440
23.1 技术要求440
23.2 处理文件441
23.3 创建一个未排序名称的文件446
23.3.1 从fgets()获取到的输入字符串中移除首尾的空白字符447
23.3.2 读取名称和写入名称448
23.4 读取未排序的人名并输出排序后的名单452
23.4.1 用链表给人名排序454
23.4.2 将排序后的名单写入输出端458
23.5 小结460
第五部分 开发大型程序
第24章 开发多文件的程序464
24.1 技术要求465
24.2 理解多文件的程序465
24.3 把声明写在头文件中,把定义写在源文件中466
24.3.1 创建源文件466
24.3.2 创建头文件467
24.4 重新审视预处理器469
24.4.1 了解预处理器的局限与风险469
24.4.2 如何有效地使用预处理器470
24.4.3 利用预处理器来调试程序471
24.5 创建多文件的程序474
24.5.1 把Card结构体与相关函数提取到相应的文件中475
24.5.2 把Hand结构体与相关函数提取到相应的文件中477
24.5.3 把Deck结构体与相关函数提取到相应的文件中479
24.5.4 完成整个dealer程序480
24.6 构建多文件的程序482
24.7 小结484
第25章 作用域485
25.1 技术要求486
25.2 从可见范围、存在范围及链接范围三方面来定义作用域486
25.2.1 可见范围486
25.2.2 存在范围487
25.2.3 链接范围488
25.2.4 综合考虑可见范围、存在范围与链接范围489
25.3 变量的作用域490
25.3.1 语句块级别的变量的作用域490
25.3.2 函数参数列表中的变量的作用域493
25.3.3 文件级别的变量的作用域493
25.3.4 全局变量494
25.4 函数的作用域495
25.4.1 作用域与信息隐藏495
25.4.2 用static关键字修饰函数496
25.5 小结500
25.6 结束语501
附录
附录A C语言的规范与关键字506
附录B 运算符优先级表格508
附录C GCC与Clang编译器的常用选项510
附录D ASCII字符集511
附录E 一个更好的字符串库:Bstrlib512
附录F Unicode与UTF-8517
附录G C语言标准库520