內容簡介
時至今日,C語言仍然是計算機領域的通用語言之一,但今天的C語言已經和初的時候大不相同了。本書主要目的就是通過一種“現代方法”來介紹C語言,書中強調標準C,強調軟體工程,不再強調“手工最佳化”。第2版修訂版中不僅有C99中的新特性,還與時俱進地增加了C11和C18中的內容。本書分為C語言的基礎特性、C語言的高級特性、C語言標準庫和參考資料4個部分。每章末尾的“問與答”部分給出一系列與該章內容相關的問題及答案,此外還包含適量的習題。
本書是C開發人員的理想參考書,在國外也被眾多大學作為C語言課程的教材。
作者簡介
【作者簡介】
K. N. 金(K. N. King)
世界知名的電腦程式設計教育家。他擁有耶魯大學計算機科學碩士學位,加州大學伯克利分校計算機科學博士學位,曾任教於喬治亞理工學院和喬治亞州立大學。除本書外,他還撰寫了廣受歡迎的著作Modula-2: A Complete Guide和Java Programming: From the Beginning。
【譯者簡介】
呂秀鋒
曾任教於北京理工大學軟體學院,講授過多門計算機課程,包括“計算機基礎(雙語)”“C語言程式設計(雙語)”“數據結構”“程式設計開發與實踐”。
黃倩
河海大學計算機科學與技術系主任,兼任中國人工智慧學會深度學習專委會委員、中國計算機學會多媒體技術專委會委員。博士畢業於中國科學院計算技術研究所,譯有《編程珠璣(第2版)》等。
【審校簡介】
李忠
資深C語言專家。著有《穿越計算機的迷霧》《X86彙編語言:從實模式到保護模式》《C語言非常道》和《標準C語言指南》等。
圖書目錄
第 1章 C語言概述 1
1.1 C語言的歷史 1
1.1.1 起源 1
1.1.2 標準化 1
1.1.3 基於C的語言 2
1.2 C語言的優缺點 3
1.2.1 C語言的優點 3
1.2.2 C語言的缺點 4
1.2.3 高效地使用C語言 5
問與答 5
第 2章 C語言基本概念 7
2.1 編寫一個簡單的C程式 7
2.1.1 編譯和連結 8
2.1.2 集成開發環境 9
2.2 簡單程式的一般形式 9
2.2.1 指令 9
2.2.2 函式 9
2.2.3 語句 10
2.2.4 顯示字元串 11
2.3 注釋 11
2.4 變數和賦值 13
2.4.1 類型 13
2.4.2 聲明 13
2.4.3 賦值 14
2.4.4 顯示變數的值 15
2.4.5 初始化 16
2.4.6 顯示表達式的值 17
2.5 讀入輸入 17
2.6 定義常量的名字 18
2.7 標識符 19
2.8 C 程式的書寫規範 21
問與答 23
練習題 25
編程題 26
第3章 格式化輸入 輸出 28
3.1 printf函式 28
3.1.1 轉換說明 29
3.1.2 轉義序列 31
3.2 scanf函式 31
3.2.1 scanf函式的工作方法 32
3.2.2 格式串中的普通字元 34
3.2.3 易混淆的printf函式和scanf函式 34
問與答 35
練習題 37
編程題 38
第4章 表達式 40
4.1 算術運算符 40
4.2 賦值運算符 44
4.2.1 簡單賦值 44
4.2.2 左值 45
4.2.3 複合賦值 45
4.3 自增運算符和自減運算符 46
4.4 表達式求值 47
4.5 表達式語句 50
問與答 50
練習題 52
編程題 54
第5章 選擇語句 56
5.1 邏輯表達式 56
5.1.1 關係運算符 56
5.1.2 判等運算符 57
5.1.3 邏輯運算符 57
5.2 if語句 58
5.2.1 複合語句 59
5.2.2 else子句 59
5.2.3 級聯式if語句 61
5.2.4 “懸空else”的問題 63
5.2.5 條件表達式 63
5.2.6 C89中的布爾值 64
5.2.7 C99中的布爾值 65
5.3 switch語句 66
問與答 69
練習題 72
編程題 74
第6章 循環 77
6.1 while語句 77
6.2 do語句 80
6.3 for語句 82
6.3.1 for語句的慣用法 83
6.3.2 在for語句中省略表達式 83
6.3.3 C99中的for語句 84
6.3.4 逗號運算符 84
6.4 退出循環 86
6.4.1 break語句 87
6.4.2 continue語句 87
6.4.3 goto語句 88
6.5 空語句 90
問與答 92
練習題 94
編程題 95
第7章 基本類型 97
7.1 整數類型 97
7.1.1 C99中的整數類型 99
7.1.2 整型常量 99
7.1.3 C99中的整型常量 100
7.1.4 整數溢出 100
7.1.5 讀 寫整數 101
7.2 浮點類型 102
7.2.1 浮點常量 103
7.2.2 讀 寫浮點數 103
7.3 字元類型 104
7.3.1 字元操作 104
7.3.2 有符號字元和無符號字元 105
7.3.3 算術類型 105
7.3.4 轉義序列 106
7.3.5 字元處理函式 107
7.3.6 用scanf和printf讀 寫字元 108
7.3.7 用getchar和putchar讀 寫字元 108
7.4 類型轉換 110
7.4.1 常規算術轉換 111
7.4.2 賦值過程中的轉換 112
7.4.3 C99中的隱式轉換 113
7.4.4 強制類型轉換 114
7.5 類型定義 115
7.5.1 類型定義的優點 115
7.5.2 類型定義和可移植性 116
7.6 sizeof運算符 117
問與答 117
練習題 120
編程題 121
第8章 數組 124
8.1 一維數組 124
8.1.1 數組下標 124
8.1.2 數組初始化 126
8.1.3 指示器 127
8.1.4 對數組使用sizeof運算符 129
8.2 多維數組 130
8.2.1 多維數組初始化 131
8.2.2 常量數組 132
8.3 C99 中的變長數組 134
問與答 135
練習題 136
編程題 138
第9章 函式 141
9.1 函式的定義和調用 141
9.1.1 函式定義 144
9.1.2 函式調用 145
9.2 函式聲明 147
9.3 實際參數 149
9.3.1 實際參數的轉換 150
9.3.2 數組型實際參數 151
9.3.3 變長數組形式參數 153
9.3.4 在數組參數聲明中使用static 154
9.3.5 複合字面量 155
9.4 return語句 155
9.5 程式終止 156
9.6 遞歸 157
9.7 泛型選擇 161
問與答 163
練習題 166
編程題 169
第 10章 程式結構 171
10.1 局部變數 171
10.1.1 靜態局部變數 172
10.1.2 形式參數 172
10.2 外部變數 172
10.2.1 示例:用外部變數實現棧 172
10.2.2 外部變數的利與弊 173
10.3 程式塊 177
10.4 作用域 178
10.5 構建C程式 179
問與答 185
練習題 185
編程題 186
第 11章 指針 188
11.1 指針變數 188
11.2 取地址運算符和間接定址運算符 189
11.2.1 取地址運算符 189
11.2.2 間接定址運算符 190
11.3 指針賦值 191
11.4 指針作為參數 192
11.5 指針作為返回值 195
問與答 196
練習題 198
編程題 199
第 12章 指針和數組 201
12.1 指針的算術運算 201
12.1.1 指針加上整數 202
12.1.2 指針減去整數 202
12.1.3 兩個指針相減 203
12.1.4 指針比較 203
12.1.5 指向複合字面量的指針 203
12.2 指針用於數組處理 204
12.3 用數組名作為指針 206
12.3.1 數組型實際參數(改進版) 207
12.3.2 用指針作為數組名 208
12.4 指針和多維數組 209
12.4.1 處理多維數組的元素 209
12.4.2 處理多維數組的行 210
12.4.3 處理多維數組的列 210
12.4.4 用多維數組名作為指針 210
12.5 C99中的指針和變長數組 211
問與答 212
練習題 213
編程題 215
第 13章 字元串 217
13.1 字面串 217
13.1.1 字面串中的轉義序列 217
13.1.2 延續字面串 218
13.1.3 如何存儲字面串 218
13.1.4 字面串的操作 219
13.1.5 字面串與字元常量 219
13.2 字元串變數 220
13.2.1 初始化字元串變數 220
13.2.2 字元數組與字元指針 221
13.3 字元串的讀和寫 222
13.3.1 用printf函式和puts函式寫字元串 222
13.3.2 用scanf函式讀字元串 223
13.3.3 逐個字元讀字元串 224
13.4 訪問字元串中的字元 225
13.5 使用C語言的字元串庫 226
13.5.1 strcpy函式 226
13.5.2 strlen函式 227
13.5.3 strcat函式 228
13.5.4 strcmp函式 229
13.6 字元串慣用法 231
13.6.1 搜尋字元串的結尾 232
13.6.2 複製字元串 233
13.7 字元串數組 235
問與答 238
練習題 241
編程題 243
第 14章 預處理器 246
14.1 預處理器的工作原理 246
14.2 預處理指令 248
14.3 宏定義 248
14.3.1 簡單的宏 249
14.3.2 帶參數的宏 250
14.3.3 #運算符 252
14.3.4 ##運算符 253
14.3.5 宏的通用屬性 254
14.3.6 宏定義中的圓括弧 254
14.3.7 創建較長的宏 255
14.3.8 預定義宏 256
14.3.9 C99中新增的預定義宏 257
14.3.10 空的宏參數 258
14.3.11 參數個數可變的宏 259
14.3.12 __func__標識符 260
14.4 條件編譯 260
14.4.1 #if指令和#endif指令 260
14.4.2 defined運算符 261
14.4.3 #ifdef指令和#ifndef指令 261
14.4.4 #elif指令和#else指令 262
14.4.5 使用條件編譯 262
14.5 其他指令 263
14.5.1 #error指令 263
14.5.2 #line指令 264
14.5.3 #pragma指令 265
14.5.4 _Pragma運算符 265
問與答 266
練習題 268
第 15章 編寫大型程式 272
15.1 源檔案 272
15.2 頭檔案 273
15.2.1 #include指令 273
15.2.2 共享宏定義和類型定義 274
15.2.3 共享函式原型 275
15.2.4 共享變數聲明 277
15.2.5 嵌套包含 278
15.2.6 保護頭檔案 278
15.2.7 頭檔案中的#error指令 279
15.3 把程式劃分成多個檔案 279
15.4 構建多檔案程式 285
15.4.1 makefile 285
15.4.2 連結期間的錯誤 287
15.4.3 重新構建程式 287
15.4.4 在程式外定義宏 289
問與答 289
練習題 291
編程題 292
第 16章 結構、聯合和枚舉 293
16.1 結構變數 293
16.1.1 結構變數的聲明 293
16.1.2 結構變數的初始化 295
16.1.3 指示器 295
16.1.4 對結構的操作 296
16.2 結構類型 296
16.2.1 結構標記的聲明 297
16.2.2 結構類型的定義 298
16.2.3 結構作為參數和返回值 298
16.2.4 複合字面量 299
16.2.5 匿名結構 300
16.3 嵌套的數組和結構 301
16.3.1 嵌套的結構 301
16.3.2 結構數組 302
16.3.3 結構數組的初始化 302
16.4 聯合 309
16.4.1 用聯合來節省空間 310
16.4.2 用聯合來構造混合的數據結構 312
16.4.3 為聯合添加“標記欄位” 312
16.4.4 匿名聯合 313
16.5 枚舉 314
16.5.1 枚舉標記和類型名 315
16.5.2 枚舉作為整數 315
16.5.3 用枚舉聲明“標記欄位” 316
問與答 316
練習題 318
編程題 323
第 17章 指針的高級套用 324
17.1 動態存儲分配 324
17.1.1 記憶體分配函式 325
17.1.2 空指針 325
17.2 動態分配字元串 326
17.2.1 使用malloc函式為字元串分配記憶體 326
17.2.2 在字元串函式中使用動態存儲分配 327
17.2.3 動態分配字元串的數組 327
17.3 動態分配數組 329
17.3.1 使用malloc函式為數組分配存儲空間 329
17.3.2 calloc函式 330
17.3.3 realloc函式 330
17.4 釋放存儲空間 331
17.4.1 free函式 332
17.4.2 “懸空指針”問題 332
17.5 鍊表 332
17.5.1 聲明結點類型 333
17.5.2 創建結點 333
17.5.3 ->運算符 334
17.5.4 在鍊表的開始處插入結點 335
17.5.5 搜尋鍊表 337
17.5.6 從鍊表中刪除結點 338
17.5.7 有序鍊表 339
17.6 指向指針的指針 344
17.7 指向函式的指針 345
17.7.1 函式指針作為參數 345
17.7.2 qsort函式 346
17.7.3 函式指針的其他用途 347
17.8 受限指針 350
17.9 彈性數組成員 351
問與答 352
練習題 355
編程題 358
第 18章 聲明 359
18.1 聲明的語法 359
18.2 存儲類型 360
18.2.1 變數的性質 361
18.2.2 auto存儲類型 361
18.2.3 static存儲類型 362
18.2.4 extern存儲類型 363
18.2.5 register存儲類型 363
18.2.6 函式的存儲類型 364
18.2.7 小結 365
18.3 類型限定符 366
18.4 聲明符 366
18.4.1 解釋複雜聲明 368
18.4.2 使用類型定義來簡化聲明 369
18.5 初始化器 369
18.6 內聯函式 371
18.6.1 內聯定義 371
18.6.2 對內聯函式的限制 372
18.6.3 在GCC中使用內聯函式 372
18.7 函式指定符_Noreturn和頭 373
18.8 靜態斷言 373
問與答 374
練習題 377
第 19章 程式設計 379
19.1 模組 379
19.1.1 內聚性與耦合性 381
19.1.2 模組的類型 381
19.2 信息隱藏 381
19.3 抽象數據類型 385
19.3.1 封裝 385
19.3.2 不完整類型 386
19.4 棧抽象數據類型 386
19.4.1 為棧抽象數據類型定義接口 386
19.4.2 用定長數組實現棧抽象數據類型 388
19.4.3 改變棧抽象數據類型中數據項的類型 389
19.4.4 用動態數組實現棧抽象數據類型 390
19.4.5 用鍊表實現棧抽象數據類型 392
19.5 抽象數據類型的設計問題 394
19.5.1 命名慣例 394
19.5.2 錯誤處理 394
19.5.3 通用抽象數據類型 394
19.5.4 新語言中的抽象數據類型 395
問與答 395
練習題 396
編程題 397
第 20章 底層程式設計 398
20.1 位運算符 398
20.1.1 移位運算符 398
20.1.2 按位取反運算符、按位與運算符、按位異或運算符和按位或運算符 399
20.1.3 用位運算符訪問位 400
20.1.4 用位運算符訪問位域 401
20.2 結構中的位域 403
20.3 其他底層技術 405
20.3.1 定義依賴機器的類型 405
20.3.2 用聯合來提供數據的多個視角 405
20.3.3 將指針作為地址使用 407
20.3.4 volatile類型限定符 409
20.4 對象的對齊 410
20.4.1 對齊運算符_Alignof 410
20.4.2 對齊指定符_Alignas和頭 410
問與答 411
練習題 411
編程題 413
第 21章 標準庫 414
21.1 標準庫的使用 414
21.1.1 對標準庫中所用名字的限制 415
21.1.2 使用宏隱藏的函式 415
21.2 C89標準庫概述 416
21.3 C99標準庫更新 417
21.4 :常用定義 418
21.5 :布爾類型和值 419
21.6 C11標準庫更新 419
21.7 :地址的對齊 420
21.8 :宏noreturn的定義 420
問與答 420
練習題 421
編程題 422
第 22章 輸入 輸出 423
22.1 流 423
22.1.1 檔案指針 424
22.1.2 標準流和重定向 424
22.1.3 文本檔案與二進制檔案 425
22.2 檔案操作 426
22.2.1 打開檔案 426
22.2.2 模式 427
22.2.3 關閉檔案 428
22.2.4 為打開的流附加檔案 428
22.2.5 從命令行獲取檔案名稱 429
22.2.6 臨時檔案 430
22.2.7 檔案緩衝 431
22.2.8 其他檔案操作 432
22.3 格式化的輸入 輸出 433
22.3.1 …printf函式 433
22.3.2 …printf轉換說明 433
22.3.3 C99對…printf轉換說明的修改 435
22.3.4 …printf轉換說明示例 436
22.3.5 …scanf函式 438
22.3.6 …scanf格式串 438
22.3.7 …scanf轉換說明 439
22.3.8 C99對…scanf轉換說明的改變 441
22.3.9 scanf示例 441
22.3.10 檢測檔案末尾和錯誤條件 442
22.4 字元的輸入 輸出 444
22.4.1 輸出函式 444
22.4.2 輸入函式 444
22.5 行的輸入 輸出 446
22.5.1 輸出函式 446
22.5.2 輸入函式 447
22.6 塊的輸入 輸出 447
22.7 檔案定位 448
22.8 字元串的輸入 輸出 451
22.8.1 輸出函式 451
22.8.2 輸入函式 452
問與答 452
練習題 455
編程題 458
第 23章 庫對數值和字元數據的支持 462
23.1 :浮點類型的特性 462
23.2 :整數類型的大小 464
23.3 :數學計算(C89) 465
23.3.1 錯誤 465
23.3.2 三角函式 466
23.3.3 雙曲函式 466
23.3.4 指數函式和對數函式 467
23.3.5 冪函式 467
23.3.6 就近捨入函式、值函式和取余函式 468
23.4 :數學計算 468
23.4.1 IEEE浮點標準 469
23.4.2 類型 470
23.4.3 宏 470
23.4.4 錯誤 470
23.4.5 函式 471
23.4.6 分類宏 471
23.4.7 三角函式 472
23.4.8 雙曲函式 472
23.4.9 指數函式和對數函式 473
23.4.10 冪函式和值函式 474
23.4.11 誤差函式和伽馬函式 474
23.4.12 就近捨入函式 475
23.4.13 取余函式 476
23.4.14 操作函式 477
23.4.15 值函式、小值函式和正差函式 477
23.4.16 浮點乘加 478
23.4.17 比較宏 478
23.5 :字元處理 479
23.5.1 字元分類函式 479
23.5.2 字元大小寫映射函式 481
23.6 :字元串處理 482
23.6.1 複製函式 482
23.6.2 拼接函式 483
23.6.3 比較函式 484
23.6.4 搜尋函式 485
23.6.5 其他函式 487
問與答 488
練習題 488
編程題 490
第 24章 錯誤處理 491
24.1 :診斷 491
24.2 :錯誤 492
24.3 :信號處理 494
24.3.1 信號宏 494
24.3.2 signal函式 494
24.3.3 預定義的信號處理函式 495
24.3.4 raise函式 496
24.4 :非局部跳轉 497
問與答 499
練習題 500
第 25章 國際化特性 502
25.1 :本地化 502
25.1.1 類項 503
25.1.2 setlocale函式 503
25.1.3 localeconv函式 504
25.2 多位元組字元和寬字元 507
25.2.1 多位元組字元 507
25.2.2 寬字元 508
25.2.3 Unicode和通用字元集 508
25.2.4 Unicode編碼 509
25.2.5 多位元組 寬字元轉換函式 510
25.2.6 多位元組 寬字元串轉換函式 511
25.3 雙聯符和三聯符 512
25.3.1 三聯符 512
25.3.2 雙聯符 513
25.3.3 :拼寫替換 513
25.4 通用字元名 514
25.5 :擴展的多位元組和寬字元實用工具 514
25.5.1 流的傾向性 515
25.5.2 格式化寬字元輸入 輸出函式 515
25.5.3 寬字元輸入 輸出函式 517
25.5.4 通用的寬字元串實用工具 518
25.5.5 寬字元時間轉換函式 521
25.5.6 擴展的多位元組 寬字元轉換實用工具 521
25.6 :寬字元分類和映射實用工具 523
25.6.1 寬字元分類函式 524
25.6.2 可擴展的寬字元分類函式 525
25.6.3 寬字元大小寫映射函式 525
25.6.4 可擴展的寬字元大小寫映射函式 525
25.7 :改進的Unicode支持 526
25.7.1 帶u、U和u8前綴的字面串 526
25.7.2 可重啟動的多位元組 寬字元轉換函式 527
問與答 528
練習題 529
編程題 530
第 26章 其他庫函式 531
26.1 :可變參數 531
26.1.1 調用帶有可變參數列表的函式 533
26.1.2 v…printf函式 533
26.1.3 v…scanf函式 534
26.2 :通用的實用工具 534
26.2.1 數值轉換函式 535
26.2.2 偽隨機序列生成函式 537
26.2.3 與環境的通信 539
26.2.4 搜尋和排序實用工具 540
26.2.5 整數算術運算函式 542
26.2.6 地址對齊的記憶體分配 542
26.3 :日期和時間 542
26.3.1 時間處理函式 543
26.3.2 時間轉換函式 545
問與答 550
練習題 552
編程題 553
第 27章 C99對數學計算的新增支持 554
27.1 :整數類型 554
27.1.1 類型 555
27.1.2 對指定寬度整數類型的限制 555
27.1.3 對其他整數類型的限制 556
27.1.4 用於整型常量的宏 557
27.2 :整數類型的格式轉換 557
27.2.1 用於格式指定符的宏 557
27.2.2 用於寬度整數類型的函式 558
27.3 複數 559
27.3.1 複數的定義 559
27.3.2 複數的算術運算 560
27.3.3 C99中的複數類型 561
27.3.4 複數的運算 561
27.3.5 複數類型的轉換規則 562
27.4 :複數算術運算 562
27.4.1 宏 562
27.4.2 CX_LIMITED_RANGE編譯提示 563
27.4.3 函式 564
27.4.4 三角函式 564
27.4.5 雙曲函式 565
27.4.6 指數函式和對數函式 565
27.4.7 冪函式和值函式 566
27.4.8 操作函式 566
27.5 :泛型數學 567
27.5.1 泛型宏 568
27.5.2 調用泛型宏 569
27.6 :浮點環境 570
27.6.1 浮點狀態標誌和控制模式 570
27.6.2 宏 571
27.6.3 FENV_ACCESS編譯提示 571
27.6.4 浮點異常函式 572
27.6.5 捨入函式 573
27.6.6 環境函式 573
問與答 573
練習題 574
編程題 575
第 28章 C1X新增的多執行緒和原子操作支持 576
28.1 :多執行緒執行支持 577
28.1.1 執行緒啟動函式 577
28.1.2 執行緒的創建和管理函式 578
28.1.3 數據競爭 581
28.1.4 互斥函式 583
28.1.5 條件變數 585
28.1.6 條件變數函式 587
28.1.7 遞歸鎖和非遞歸鎖 591
28.1.8 初始化函式 591
28.1.9 _Thread_local 存儲類和執行緒存儲期 593
28.1.10 執行緒專屬存儲 595
28.1.11 執行緒專屬存儲函式 596
28.2 _Atomic、:原子類型和原子操作支持 599
28.2.1 _Atomic:類型指定符 類型限定符 600
28.2.2 標準庫定義的原子類型 600
28.2.3 初始化原子變數 601
28.2.4 原子變數的初始化函式 601
28.2.5 原子操作 602
28.2.6 原子操作函式 604
28.2.7 記憶體順序 608
28.2.8 圍欄函式 613
28.2.9 鎖無關判斷函式 615
28.2.10 原子標誌類型及其操作函式 616
問與答 619
練習題 619
編程題 620
附錄A C語言運算符 621
附錄B C1X與C99的比較 622
附錄C C99與C89的比較 624
附錄D C89與經典C的比較 628
附錄E標準庫函式 631
附錄F ASCII字元集 673
延伸閱讀 674
索引(圖靈社區下載)