本書從計算機基礎知識講起,繼而介紹標準C語言的內容。除此之外,書中還包含其他教材沒有而C編程又必需的若干重要內容。
本書深入淺出,文字簡練,將復雜的問題簡單化,內容全面而篇幅不大;對各章節的重點、難點把握準確,處理得當;注重培養編程思維能力,對編程時易犯的錯誤,點評到位。書中對C語言中最重要的內容——函數、指針、數組、文件四部分的編寫,比主流教材上升了一個層次。尤其是指針部分,全面糾正了多年以來主流教材中的若干錯誤,給出了明晰、準確的說法和定義。
本書作者講授C語言二十多年,有豐富的編程和教學經驗,對學生的思維方式和學習狀況非常了解,對C語言的知識體系爛熟于心。在書中,作者奉獻了自己對許多問題的獨到見解。書中大量的編程經驗和注意事項,蘊含著作者長期的積累,凝聚著C語言的精華。
本書非常適合作為高等學校各專業程序設計基礎、C語言程序設計等課程的正式教材,也可作為自學教材或學習參考書。
C語言是高等學校計算機及相關專業必修的專業基礎課,是培養學生算法思維能力和動手能力的主要課程,也是面向對象程序設計、數據結構等后續課程的先導課。學生對C語言的掌握情況很大程度上決定著大學四年的學習情況。
鑒于C語言的重要地位,近些年來出現了無數的C語言教材,但幾乎所有教材在內容和順序上都千篇一律,存在許多問題。有些問題是致命的,導致長期以來國內眾多教師和學子對一些知識的理解出現嚴重偏差,使C語言的教與學走入誤區。雖然有些教材在形式上做了不少改進,如案例教學法、啟發式教學法等,但都是表面文章,核心內容并無變化,教材中的問題依然存在。
作者講授C語言多年,對目前國內教材在諸多方面的缺陷和錯誤給廣大學子造成的危害深感憂慮。曾幾次動筆,都因懶惰而擱置。未能成書的另一個原因,是多年來一直覺得能等到一本較高質量、沒有重大錯誤的教材,然而終無所見,于是,編寫了本書。
編寫本書的指導思想
(1) 針對剛入大學的新生,將C編程所需的一些必要的計算機知識納入本書。
(2) 按符合學生認知規律的自然順序安排章節,而不是為了所謂的“系統”、“全面”不顧及知識點的自然順序把前后相關的所有內容都堆放在一起。那樣做很容易把初學者的思維搞亂,因為對于一個初學者來說,理順眾多知識點之間的關系很難。
(3) 化繁為簡、化整為零。重要的知識點單獨寫成一章,每章內容相對獨立,與其他知識點關聯少,條理清楚,易于初學者掌握。
(4) 對目前絕大多數教材都出現嚴重錯誤的“指針”一章的內容和絕大多數教材都語焉不詳的“文件”一章的內容重點著墨。糾正主流教材中的諸多錯誤說法和錯誤代碼,澄清若干似是而非的問題。
(5) 將作者多年積累的教學經驗、對若干問題的獨到見解、編程注意事項、典型例題和習題寫到書中,奉獻給廣大師生和讀者。
與其他教材相比,本書在以下幾方面做了較大改進。
1. 對教材內容的改進
1) 增加了以下幾部分的內容
要學好C語言,下面的知識是必要的,但幾乎所有教材對以下內容都未涉及。[1]〖2〗深入淺出新編C程序設計教程[1]前言〖2〗(1) 計算機基礎知識。絕大多數學校都把C語言放在大一的第一學期開設,對于沒有任何計算機基礎知識的新生來說,C語言的知識仿佛“天書”。因此,本書從計算機基礎知識講起。這些基礎知識包括內存和內存地址的概念,二進制,不同數制之間的轉換,原碼、反碼和補碼的求法,計算機語言及語言處理過程等。
(2) 有關路徑和輸入輸出重定向的概念。C語言中,很多地方需要用到路徑和輸入輸出重定向的概念,故也把這兩部分內容編入本書。其中路徑部分放在第1章,作為選講或自學的內容;輸入輸出重定向放在附錄中,供需要的讀者自行學習。
(3) 緩沖區及鍵盤緩沖區的概念。學習C語言的輸入輸出,緩沖區是個繞不開的話題。如果不知道數據從鍵盤到緩沖區的處理過程,就很難掌握輸入輸出,就很難解釋為什么程序會出現那些意想不到的運行結果。
(4) 函數的作用和函數設計的原則。函數是被調用的,因此函數的適用性和靈活性是衡量一個函數優劣的重要指標。多數教材只注重講解函數定義和函數調用的格式、函數參數傳遞的特點,對于函數的作用和設計原則(追求通用性、可利用率等)極少談及。本書從函數返回值的設定以及參數設定兩方面詳細講述函數設計的原則。
(5) 文件操作原理及相關細節問題。文件一章的內容非常重要,但又特別難懂。難懂的原因有三: 一是幾乎所有教材都未給出文件操作的原理,學生知其然,不知其所以然;二是有幾個概念特別容易混淆,如寫數據有文本和二進制兩種方式,文件分文本和二進制兩類文件,文件的打開方式也分文本方式和二進制方式。所有教材都未明確指出它們之間有無關聯,區別是什么,導致學生概念混亂;三是幾乎所有的教材在介紹文件操作時都語焉不詳,對一些重要內容不予講解,導致學生一編程就出錯,望文件而生畏。本書對上面所說問題均做了詳細講述并予以例證。
2) 糾正了主流教材中的若干錯誤
(1) 糾正了幾乎所有教材都存在的關于指針的一些錯誤說法。例如,“指針就是地址”、“若有定義int a\[10\],*p=a;,則p指向數組a”、“若有定義int a\[3\]\[5\],*p=a;,則p是指向二維數組的指針”、“指向字符串的指針變量”、“數組名就是數組的首地址”、“&是取地址運算符”等錯誤說法。
(2) 對文件操作中的一些問題進行了糾正或澄清。例如,函數feof()何時返回非零值問題(多數教材所講都是錯的)、用二進制方式能否打開文本文件、用文本方式打開文件后能否以二進制方式向其中寫數據等問題。
(3) 澄清了共用體變量能否初始化、共用體變量能否作為參數等問題。
2. 對各章節的內容分配及前后順序都做了較大調整和優化
1) 對指針內容的分解
指針是C語言的精華,但指針又非常難學。因為C語言中指針的類型很多。如此多的類型本就容易混淆,一般教材又把它們全部放在一章中講解,顯得很全面、很系統。但學生要在一章中(兩周的時間)弄懂如此多抽象難懂的內容,實在是勉為其難。實際效果表明,這樣安排很不合理。也正是因為這樣安排才使得指針如此難學。
本書將指針最重要的兩個應用——用指針變量訪問變量、用指針變量訪問下標變量兩部分抽出來作為單獨的兩章來講解。其中,“用指針變量訪問變量”一章放在函數之后、數組之前講解;“用指針變量訪問下標變量”一章放在數組之后講解,其余內容放在“指針綜述”一章中介紹。如此分解可化繁為簡,具有重點突出,針對性強,易于接受等優點,也彰顯了指針的這兩個重要用途。另外,這樣的設計也可把對指針的學習從短短一兩周的時間擴展到前后約一個月的時間。較長時間的消化,有利于學生更好地理解指針、掌握指針。
2) 各章節順序的調整
多數教材在以下章節的安排順序上存在問題。
(1) 數組和指針的順序問題。一般教材都是先講數組,再講指針。帶來的問題就是,無法對數組名進行解釋,于是產生了“數組名是個地址”的錯誤說法。實際上數組名在多數情況下都是一個指針。在不介紹指針的情況下,很難把數組一章的內容講清、講透。
先講數組再講指針,也無法講明在數組名作為參數的情況下被調函數形參int x\[\]中的x是個指針變量,只好把它說成是“與實參數組具有相同地址的數組”,不僅難以令人信服,而且對很多現象(比如為什么x可以進行自增運算)也無法解釋。
(2) 數組和函數的順序問題。一般教材都是把函數放在數組之后講解,原因是便于把“數組名作參數”放在函數一章中。看起來似乎歸類得當,豈不知這樣一來就掩蓋了函數一章的重點。函數一章,最應該教給學生的是如何把函數設計得當、便于其他函數調用,只應突出這一重點。如果把數組問題也放在函數一章中,就會喧賓奪主,因為數組名作參數本身也是非常重要的一個知識點。
綜上所述,最合適的順序安排是函數、指針(1)、數組、指針(2)、指針綜述。
本書的使用建議
建議理論授課學時數: 48~56。建議實驗學時數: 24~32。
第1章計算機基礎知識,若授課對象不是大一第一學期新生,已有基礎,可以不講,或只講需要的部分。其中帶星號的內容(路徑及其表示)為選講內容。
第16章編譯預處理,未必到最后才講,可根據情況放在適當時候講解,如放在第8章之后。
本書適用對象: 高等院校本、專科所有開設程序設計基礎或C語言程序設計課的學生,或自學C語言的讀者。
其他說明
1. 本書所用編譯器
本書講解時兼顧Visual C++(簡稱VC)6.0和Turbo C 2.0,但程序主要是針對VC編寫的,所有源程序都在VC中調試、運行過,例題中的運行結果都是在VC中得到的。
2. 例題和源代碼
本書配套資料(可從www.tup.com.cn下載)中含有全部103個例題源代碼,例題編號與源程序的編號一一對應。例如,例2.1的源代碼對應資料中的源文件s2_1.c,若該例題有3種解法,則對應的源文件分別是s2_1_1.c、s2_1_2.c和s2_1_3.c。
本書的編寫獲2014年山東省普通高校應用型人才培養專業發展支持計劃項目和2012年山東省高等學校教學改革項目的資助。我校專業共建合作伙伴——浪潮優派科技教育有限公司總裁邵長臣先生審閱了全書,并提出很多寶貴的意見,在此致以誠摯的謝意。原達教授、謝青松教授也對本書的編寫給予熱情幫助和大力支持,在此向以上兩位深表謝意。此外,本書的編寫參考了大量的書籍和文獻資料,謹向這些書籍和文獻資料的作者表示感謝。本書在編寫出版過程中也得到了清華大學出版社的大力支持和幫助,在此一并表示感謝。
由于時間倉促和作者水平所限,書中難免疏漏和欠妥之處,請各位專家、讀者不吝指正。
作者
第1章計算機基礎知識1
1.1計算機的硬件組成1
1.1.1運算器1
1.1.2控制器1
1.1.3存儲器1
1.1.4輸入設備3
1.1.5輸出設備3
1.2數制及數制間的轉換3
1.2.1二進制3
1.2.2八進制5
1.2.3十六進制5
1.3原碼、反碼和補碼6
1.3.1原碼6
1.3.2反碼6
1.3.3補碼6
1.4路徑及其表示6
1.4.1路徑的概念6
1.4.2當前盤和當前目錄7
1.4.3絕對路徑和相對路徑7
1.5計算機語言8
1.5.1機器語言8
1.5.2匯編語言9
1.5.3高級語言10
1.6算法11
1.6.1算法的概念11
1.6.2算法的特性12
1.6.3算法的表示12
1.6.4程序的3種基本結構13[1]〖2〗深入淺出新編C程序設計教程[1]目錄〖2〗習題114
第2章C程序和C編譯器簡介16
2.1C語言及C標準簡介16
2.1.1C語言的出現16
2.1.2C語言的特點16
2.1.3C標準17
2.2簡單的C程序18
2.3C程序的構成22
2.4C編譯器及操作簡介24
2.4.1Turbo C 2.0編程環境及常用操作簡介24
2.4.2Visual C++6.0編程環境及常用操作簡介28
習題233
第3章C編程基礎知識35
3.1常量和變量35
3.1.1常量35
3.1.2變量35
3.2基本數據類型40
3.2.1整型數據40
3.2.2實型數據42
3.2.3字符型數據45
3.2.4字符串47
3.3符號常量和常變量48
3.3.1符號常量48
3.3.2常變量48
3.4運算符和表達式49
3.4.1算術運算符49
3.4.2賦值運算符和賦值表達式50
3.4.3自增自減運算符51
3.4.4逗號運算符和逗號表達式53
3.4.5類型轉換運算符54
3.5數據的類型轉換55
習題355
第4章順序結構程序設計59
4.1賦值語句59
4.1.1賦值語句及其執行過程59
4.1.2賦值的幾種數據處理方式59
4.2輸入輸出函數63
4.2.1緩沖區的概念及作用63
4.2.2getchar()和putchar()64
4.2.3printf()和scanf()65
4.3順序結構程序設計舉例70
習題472
第5章選擇結構程序設計76
5.1關系運算符和關系表達式76
5.1.1關系運算符76
5.1.2關系表達式76
5.2邏輯運算符和邏輯表達式77
5.2.1邏輯運算符77
5.2.2邏輯表達式78
5.3if語句79
5.3.1if語句的格式79
5.3.2if語句的使用說明80
5.3.3嵌套的if語句83
5.3.4if語句應用舉例85
5.3.5if語句編程的常見問題87
5.4條件運算符和條件表達式92
5.5switch語句93
5.5.1switch語句的格式及執行過程94
5.5.2switch語句應用舉例96
5.5.3switch語句編程的常見錯誤97
習題598
第6章循環結構程序設計104
6.1循環及其實現思想104
6.2循環語句105
6.2.1while循環105
6.2.2dowhile循環107
6.2.3for循環108
6.2.43種循環的比較110
6.3循環的控制111
6.3.1計數器控制循環和其他條件控制循環111
6.3.2break和continue112
6.3.3循環結束后循環變量的值與終值的比較115
6.4多重循環116
6.5循環編程舉例117
習題6126
第7章函數132
7.1函數的作用132
7.2函數的定義134
7.2.1函數定義的格式134
7.2.2函數的返回值134
7.2.3函數參數的設置138
7.3函數的調用140
7.3.1函數調用前的聲明140
7.3.2函數調用的方式142
7.4函數的參數傳遞143
7.4.1形參與實參143
7.4.2參數的傳遞143
7.4.3參數傳遞的單向性144
7.5函數的嵌套調用145
7.6遞歸函數146
7.6.1遞歸的條件146
7.6.2遞歸函數的執行過程147
7.6.3遞歸與迭代149
7.7函數編程舉例150
7.8內部函數和外部函數153
習題7154
第8章變量的作用域和存儲類別158
8.1變量的作用域158
8.1.1局部變量158
8.1.2全局變量158
8.2同名變量的辨析160
8.3變量的存儲類別和生存期162
8.3.1內存的存儲區域162
8.3.2動態變量162
8.3.3靜態變量163
8.4變量的作用域和生存期164
習題8165
第9章用指針變量訪問變量168
9.1指針和指針變量168
9.1.1指針和指針變量的概念168
9.1.2直接尋址和間接尋址169
9.1.3指針變量的值、地址及類型171
9.2通過指針變量訪問變量171
9.2.1指針變量的定義171
9.2.2指針變量的賦值172
9.2.3通過指針變量間接訪問一個變量173
9.3指針變量在函數傳遞中的作用173
習題9178
第10章數組181
10.1一維數組181
10.1.1一維數組的定義181
10.1.2一維數組的元素構成及一維數組的存儲結構182
10.1.3數組名的指針類型182
10.1.4數組元素的表示方法183
10.1.5一維數組的引用184
10.1.6一維數組的初始化186
10.1.7一維數組應用舉例186
10.2二維數組191
10.2.1二維數組的定義191
10.2.2二維數組的元素構成及二維數組的存儲結構192
10.2.3二維數組名的指針類型192
10.2.4二維數組中下標變量的表示方法193
10.2.5二維數組的引用194
10.2.6二維數組的初始化195
10.2.7二維數組應用舉例195
10.3字符數組和字符串處理函數196
10.3.1字符數組196
10.3.2字符串處理函數197
10.3.3字符數組應用舉例201
習題10203
第11章用指針變量訪問下標變量208
11.1用指針變量訪問下標變量的方法208
11.1.1知識回顧208
11.1.2用指針變量訪問一維數組中的下標變量208
11.1.3用指針變量訪問二維數組中的下標變量210
11.2用指針變量訪問下標變量的適用場合211
習題11214
第12章指針綜述218
12.1指針類型簡介218
12.2指向變量的指針219
12.2.1指向變量的不可變指針219
12.2.2指向變量的指針變量219
12.3指向數組的指針220
12.3.1指向一維數組的不可變指針220
12.3.2指向一維數組的指針變量221
12.3.3指向一維數組的指針變量的適用場合222
12.4指針與字符串223
12.4.1字符串的表示方式223
12.4.2用指針變量處理字符串225
12.5指針與函數227
12.5.1函數的入口地址227
12.5.2指向函數的指針變量227
12.5.3指向函數的指針變量的作用228
12.5.4指針函數229
12.6指針數組230
12.6.1指針數組的定義230
12.6.2指針數組的引用231
12.6.3指針數組應用舉例231
12.7指向指針變量的指針231
12.7.1指向指針變量的不可變指針231
12.7.2指向指針變量的指針變量232
12.7.3應用舉例232
12.8帶參數的main()函數235
12.8.1C語言對main()函數參數的規定235
12.8.2帶參數main()函數的作用235
12.8.3帶參數的main()函數的執行過程236
12.8.4程序舉例236
12.9動態內存分配237
12.9.1動態內存分配函數237
12.9.2動態內存分配舉例238
習題12239
第13章數據類型的自定義244
13.1結構體的定義和結構體變量的定義244
13.1.1結構體的概念和結構體的定義244
13.1.2結構體變量的定義和空間分配246
13.1.3結構體變量的初始化248
13.1.4結構體數組的定義和初始化249
13.2結構體變量的引用249
13.2.1結構體變量的引用方法249
13.2.2結構體變量引用舉例250
13.3用指針變量操作結構體變量251
13.3.1為什么要通過指針變量訪問結構體變量251
13.3.2應用舉例252
13.4鏈表及鏈表操作簡介253
13.4.1鏈表的概念253
13.4.2使用鏈表的優點254
13.4.3鏈表操作簡介254
13.5共用體259
13.5.1共用體的概念259
13.5.2共用體的作用260
13.5.3共用體及共用體變量的定義261
13.5.4共用體變量(數組)的初始化262
13.5.5共用體變量的引用262
13.6枚舉類型263
13.6.1枚舉類型的定義263
13.6.2枚舉變量的定義264
13.6.3枚舉變量的使用264
13.6.4枚舉應用舉例264
13.7用typedef定義類型別名265
習題13267
第14章位運算270
14.1C語言中的位運算符270
14.2位運算及應用271
14.2.1按位與271
14.2.2按位或272
14.2.3異或273
14.2.4取反274
14.2.5左移274
14.2.6右移275
習題14276
第15章文件278
15.1文件及相關的概念278
15.1.1文件的范疇278
15.1.2文件中存儲數據的兩種方式278
15.1.3文件的種類279
15.1.4文件操作函數及緩沖區的概念280
15.2文件讀寫的原理281
15.3文件的讀寫位置指針和文件結束標志282
15.3.1讀寫位置指針282
15.3.2文件結束標志282
15.4文件的打開和關閉283
15.4.1文件的打開283
15.4.2文件的關閉289
15.5文件的讀寫290
15.5.1fgetc()和fputc()291
15.5.2fread()和fwrite()293
15.5.3fgets()和fputs()297
15.5.4fscanf()和fprintf()298
15.6讀寫位置指針的移動和定位300
15.6.1移動讀寫位置指針的函數300
15.6.2兩個與讀寫位置指針有關的函數301
15.7文件的出錯檢測302
15.8文件操作舉例303
習題15307
第16章編譯預處理310
16.1宏定義310
16.1.1無參宏定義310
16.1.2有參宏定義311
16.1.3嵌套的宏定義312
16.2文件包含312
16.2.1文件包含的格式312
16.2.2文件包含的作用313
16.2.3文件包含兩種格式的區別313
16.3條件編譯314
16.3.1條件編譯的格式314
16.3.2條件編譯應用舉例316
習題16317
附錄AC語言規約320
附錄B輸入輸出重定向322
附錄CC語言的關鍵字325
附錄D常用字符與ASCII碼對照表326
附錄E運算符的優先級和結合性327
附錄F常用庫函數329
參考文獻334