本書以C語言為基礎,系統地介紹程序語言、算法與數據結構以及高級編程技術。全書由13章組成,以程序設計語言、程序設計方法和程序設計技術三大主題組織教材內容,采用了“數據表示”和“程序實現”雙線索知識體系,優化了程序設計知識的安排。
本書結構清晰、語言通俗易懂,示例代碼具有專業的編程風格;內容由淺入深、知識循序漸進,例題豐富,體現了程序設計和算法、數據結構的緊密結合。本書注重典型案例的精選與提煉。本書的高級編程技術內容便于開展課程設計和研究型學習。本書配套有經過多年教學實踐的程序設計綜合訓練平臺。
本書可作為高等院校理工類專業和信息技術類培訓機構“程序設計”、“軟件開發技術”課程的教材,也可作為計算機程序設計愛好者學習程序開發和編程技術的自學教材。
程序設計是大學計算機基礎教育和計算機專業基礎的核心課程,它既為其他技術課程奠定程序開發基礎,又是其他專業課或實踐環節的軟件工具,因此成為各類專業的必修課程。程序設計覆蓋面廣、影響大,是卓越工程師教育培養計劃的通識教育基礎,同時也是大學生參加課程設計、畢業設計、創新實驗、科技制作和學科競賽等活動的重要平臺。
C語言是國內外廣泛使用的計算機程序設計語言。其功能強大、靈活自由、數據表示豐富、代碼運行效率高、可移植性好,囊括了高級語言和低級語言各自的優點,適合編寫系統軟件和各類應用程序。世界上大多數軟件都是由C語言和C++語言開發的,在TIOBE編程語言排行榜上,C語言、C++語言及其衍生發展起來的Java語言多年來始終處在前三位。學習程序設計從C語言入手,對于培養算法設計與分析能力、抽象數據描述與表示能力以及利用計算機求解現實問題的計算思維能力具有其他語言無法比擬的優點。而且在完全掌握了C語言之后,再學習其他程序語言就會輕車熟路。
然而,C語言的學習難度也是很大的。很多學生往往是“考完即忘”,學了后面的忘了前面的,低年級時學習的程序設計到了高年級即處于猶如從未學過的狀態,更談不上利用程序設計解決實際應用問題。而且面對龐大、復雜的C語言知識系統,不少學生甚至教師在教與學的過程中始終感覺“只見樹木,不見森林”,對學過的程序思路不甚了解、數據描述不清楚、算法設計不到位,最后連最基本的語言知識也掌握不住,最基本的開發環境也不會使用。缺少以技能為目標的程序設計教材是造成這一局面的重要原因之一。
現有的C語言和C++程序設計類的教材多偏重語言知識,羅列語法多、千篇一律、大同小異,在如何應用程序解決實際問題方面下的工夫少;程序設計方法與語言結合少,缺少推動學生計算思維的訓練;生硬的例子與實際應用脫節,缺少應用編程技術的展開。教學中盡管有諸如“案例教學”、“項目驅動”的做法,但由于缺少成熟的教學平臺和系統化、規范化的教學資源,難以培養和提高學生應用程序設計解決實際問題的技能。
需要知道,人類學自然語言時,學的不僅是聽還有說;學字時,學的不僅是讀還有寫。隨著人們向一個越來越數字化的信息世界邁進,不僅應該學會如何使用程序,還要學會如何編寫程序。當語言知識轉化為編程技能時,就沒有知識會遺忘了,應用程序設計解決實際問題的計算能力如同學習語言時的聽、說、讀、寫一般。
為此,我們在多年程序設計課程的一線教學經驗和軟件開發科研工作基礎上,結合自主研發的程序設計綜合訓練平臺和系列教育軟件,推出以語言知識為工具、以技能培養為目標、以編程技術為核心的系列程序設計教材。 本教材遵循我們多年提倡的“精講多練、注重技能、開拓設計”教學理念編寫。在程序語言知識體系的選取與深度的把握上,在算法、數據結構與程序設計的結合上精心設計,力圖適合高等院校和專業計算機培訓的教學目標與知識結構的要求,體現了以下幾個特色。
(1) 首創雙線索的程序設計知識體系。
任何一本程序設計教材必然是以程序語言為背景的,本書也不例外。然而C語言具有龐大的語言知識內容,因此以語言知識為教學線索必然是整體感凌亂。表現為教學學時始終處在不夠的“高壓狀態”,學生學習始終抓不住主次。
本教材的雙線索程序設計知識體系以“數據表示”和“程序實現”作為教學上的兩條主線索,螺旋上升、交叉,推進,如圖0.1所示。
圖0.1 雙螺旋線索C語言知識體系示意
首先,教材通過簡單程序引出程序基本結構,以編程為目標給出兩條線索:數據表示和程序實現。其次,從引入簡單數據開始,逐步解決運算和程序組織,進而上升到程序模塊化的實現。然后,從基本類型提高到復雜數據類型,上升到數據結構層面的數據表示,程序模塊進階到算法實現。最后,兩條線索交匯到高級編程技術應用專題,揭示程序設計與應用軟件開發的一般規律。
實際教學效果表明,雙線索程序語言知識體系突出了程序設計方法學,使程序語言成為服務于編程的工具而不是目標,學習者既能獲取語言知識,又能掌握編程技能。
(2) 優化程序設計知識安排。
多數現有教材中的知識安排導致以技能為目標的程序設計難于實現,出現教學瓶頸。表現在語言階段冗長,使得以函數、自定義類型等內容為教學中心的編程階段在實際教學中接近課程末期,從而讓應用程序設計教學目標落空。
本教材在程序語言知識方面采用了“快節奏”,在程序設計方法和編程技術方面采用了“慢節奏”,解決了多年來程序設計教與學的難題和瓶頸問題。“快節奏”體現為語言基礎知識學時被大幅度壓縮, 從一開始即以簡單程序框架展開程序知識,直接進入以程序模塊化為主的教與學環境。方便教師精講知識,學生早早練習進而多練,教材不在語言細節、小片段程序上反復循環。“慢節奏”體現為以(較難的)編程技術為研究專題展開(費時的)編程方法教學,方便教師組織技能訓練,學生獲取編程技巧。本教材將軟件開發中的結構化、面向對象、組件模型和敏捷思想融入每個章節,讓學習者接受專業化訓練。
如圖0.2所示是本教材的知識安排,與傳統的C語言教學相比,增加了“設計階段”的教學。顯然,優化的知識體系使教師在教學時能夠“抓大”(設計方法)“放小”(語言知識),學生學習時能夠得到最大化的“飽滿感”編程訓練。
圖0.2 優化的C語言程序知識安排
(3) 首創高級編程技術教學新思想。
由于沒有更高層次的應用程序開發內容,許多教材的實際教學效果就是教師和學生都集中在做題上面。如數學一般,將程序設計演變成“程序語言 +計算方法”, C語言成了數學工具。殊不知計算方法(數值計算、非數值計算)僅是程序設計方法的一種,程序方法學中還有諸如操作系統、人機界面、圖形圖像、多媒體、網絡通信、數據庫、硬件接口等技術領域,每個領域都有獨特的編程技術和精巧的解決方法。
衡量程序設計教學效果有兩個重要指標:編程累計行數(TLOC)和單個程序行數(SLOC) 。以解題為主的編程訓練能提高TLOC,但卻止步于SLOC。即使將習題做上百題,雖然TLOC指標上去了,但SLOC卻不見長。一般地,在專業的軟件開發技術領域,SLOC小于300行時很難讓人體會到應用開發的“感覺”.
高級編程技術是本教材主要的創新成果之一。通過研究型專題的技術教學,拓寬了學生的知識面,使其充分認識到程序是如何解決應用問題的,有極大的興趣展開研究型學習。在這樣的教與學環境下,才能從根本上提高SLOC,提升技能訓練層次。
(4) 注重程序設計和算法、數據結構的緊密結合。
程序設計與算法、數據結構實際上是一個統一體,不應該也不可能將它們對立與分割。我國計算機基礎教育的實際情況是,不少非計算機專業在程序設計課程后不再涉及算法和數據結構。即使是計算機專業開設有專門的算法和數據結構課程,也是“自說自話”,并不是站在軟件系統開發(SSD)的角度使之有機地聯系在一起。
算法和數據結構是程序設計的理論升華,是培養學生向應用程序開發轉型的主要工具。本教材給出算法和數據結構的初步知識,克服了簡單羅列算法、數據結構內容和算法與程序設計脫節、數據結構與程序數據表示脫節的問題。在講述每一種常用算法和數據結構的基本思路與設計步驟的基礎上,落實到每一個案例求解,從案例的提出到算法設計與數據描述、從程序實現到案例結果的討論與分析,環環相扣,融為一體,力求理論與實際相結合,數據描述與數據表示、算法與程序實現相統一,切實提高對所學算法、數據結構的理解和掌握。
(5) 注重典型案例的精選與提煉。
培養學生的學習興趣,激發學生的學習熱情,不是一兩句空洞說教所能奏效的,必須通過一些有價值的實際案例來引導。本教材設計了初等難度語言示范型、中等難度算法和數據結構應用型、較高難度綜合設計型三種梯度的案例。這些案例的精選與提煉,有利于提高學生學習程序設計的興趣,有利于學生在計算機現實問題求解上開闊視野,使之在程序設計方法和思路的開拓與編程技巧的應用上有一個深層次的鍛煉與提高。其中難度較大的高級編程技術綜合設計案例可作為課程設計、大作業與課后專題研究選用。
算法、數據結構與程序設計都不是一成不變的,可以實施多層次多方位的變通,變通出效果,變通長能力。本教材的部分示例給出了算法改進與程序優化的過程,既是提高案例求解效率的過程,也是算法設計能力培養與提高的過程,更是優化意識與創新能力增強的過程。
(6) 注重編程風格。
本書使用ISO/IEC 9899:1999 C語言標準(簡稱C99標準),充分體現了程序語言的最新進展和當前業界的最佳實踐。
書中廣泛采納各專業軟件公司編程規范的優點,無論語法語義、書寫形式、示例代碼等,均采用專業編程風格編寫,潛移默化地引導學習者與專業化接軌。
書中所有程序均在Visual C++ 6.0和GCC 4.x (Code::Blocks)上調試通過。同時,教材中的所有源程序與各章習題的完整代碼均可在清華大學出版社網站下載。
(7) 配套程序設計教學平臺、系列教育軟件和教學資源。
學習程序設計,上機實驗是重要的環節。而實驗環節重要的是什么呢?是性能優越的計算機或者環境良好的機房嗎?答案不是。那種在實驗課上做題、講題的教學模式是很難培養程序設計技能的,本質上這種模式一開始就是奔期末考試(等級考試)去的。
程序設計實驗環節最重要的是要有優秀的教學平臺、教育軟件和完整的教學資源。以技能培養為目標、以編程技術為核心的教學模式不是傳統實驗手段自發實現的,而是通過高集成度的程序設計綜合訓練平臺,全程自動化輔助教學和教學管理來實現的。
自2001年以來,基于專業的軟件開發科研優勢,結合一線教學和課程改革的經驗,圍繞課堂、實驗、作業、設計、考核5個教學環節,我們開發了系列教育軟件。例如,“程序設計在線評測系統INPOJ”采用計算機應用系統使學生通過大量習題的訓練提高解題速度(POJ訓練)以解決TLOC; “軟件設計協同開發平臺DevForge”按專業軟件開發方式引導、跟蹤、自動評閱學生課程設計程序和報告以解決SLOC; “遠程網絡考試系統inTest”實現技能測試和實踐考核,等等。這些教學平臺的使用,使得實驗機房變成了學生討論、思考、相互教授的研究場所,形成數字化課堂教學、網絡輔助教學、電子教室、智能答疑、綜合訓練等立體化教學環境,為落實教學理念和教學目標提供了先進工具。
使用本教材的高等院校和培訓機構想要進一步了解有關程序設計綜合訓練平臺和系列教育軟件更多的信息,請與作者(jxf@nwpu.edu.cn)聯系。
本書有兩本配套的教學參考書:
(1) 《C程序設計實驗教程》。該書分為4部分。前兩部分詳細介紹了Visual C++和GCC開發工具的使用方法和程序調試技術;第三部分是與教材知識體系相對應的實驗內容,分為驗證型實驗和設計型實驗,主要突出綜合性實驗,并結合算法、數據結構知識設計了一些有難度的實驗題目;第四部分是課程設計專題研究實驗內容,其目的是使讀者能夠訓練應用程序開發,獲取設計C程序項目的初步知識和工程經驗,掌握高級編程技術。
(2) 《C程序設計習題與解析》。該書主要包括3個方面的內容:知識點與考點提煉、經典例題解析、典型習題與解答。內容緊扣課程教材和實驗教材,對課程的講授、學習以及考查起到積極的指導和輔助作用,其目的是使讀者加強程序語言知識的掌握。
此外,向使用本書的教師提供講課的電子演示文稿和素材,以節省教師的備課時間。向使用本書的高校和培訓機構提供“程序設計課程教學指南”,方便組織教學、實施課程管理。
本書第1~7章和第13章由姜學鋒編寫,第8~12章由曹光前、姜學鋒編寫,全書由姜學鋒主編并統稿。在書稿的編著過程中,得到了多位專家的關心和熱情支持,西北工業大學計算機學院的同事們提出了許多寶貴的意見和建議,清華大學出版社對本書的出版十分重視并做了周到的安排。在此,對所有鼓勵、支持和幫助過本書編寫工作的領導、專家、同事和廣大讀者表示真摯的謝意!
由于時間緊迫以及作者水平有限,書中難免有錯誤、疏漏之處,懇請讀者批評指正。
姜學鋒2011年7月于西北工業大學
第1章 程序設計基礎11.1 計算機系統和工作原理1
1.1.1 計算機系統的組成1
1.1.2 指令與程序3
1.2 信息的表示與存儲5
1.2.1 計算機的數字系統5
1.2.2 進位計數制的轉換6
1.2.3 數值數據的表示9
1.2.4 非數值數據的表示13
1.3 程序設計語言14
1.3.1 機器語言與匯編語言14
1.3.2 高級語言15
1.4 程序設計概述16
1.4.1 計算機問題求解的基本特點16
1.4.2 算法的定義與特性17
1.4.3 算法的表示17
1.4.4 結構化程序設計19
1.4.5 面向對象程序設計20
1.4.6 程序設計技術前沿21
1.5 C語言概述21
1.5.1 C語言的歷史與特點21
1.5.2 C語言基本詞法22
1.5.3 簡單的C程序24
1.5.4 C程序基本結構26
1.5.5 C程序開發步驟27
1.5.6 C程序編碼風格28
習題28第2章 數據類型與表達式30
2.1 數據類型30
2.1.1 整型31
2.1.2 浮點型32
2.1.3 字符型33
2.2 常量34
2.2.1 整型常量34
2.2.2 浮點型常量35
2.2.3 字符常量35
2.2.4 字符串常量37
2.2.5 符號常量38
2.3 變量39
2.3.1 變量的概念39
2.3.2 定義變量39
2.3.3 使用變量40
2.3.4 存儲類別41
2.3.5 類型限定41
2.4 運算符與表達式42
2.4.1 運算符與表達式的概念42
2.4.2 算術運算符45
2.4.3 自增自減運算符46
2.4.4 關系運算符47
2.4.5 邏輯運算符48
2.4.6 條件運算符50
2.4.7 位運算符51
2.4.8 賦值運算符55
2.4.9 取長度運算符57
2.4.10 逗號運算符57
2.4.11 圓括號運算符58
2.4.12 常量表達式58
2.5 類型轉換59
2.5.1 隱式類型轉換59
2.5.2 顯式類型轉換61
習題62
第3章 程序控制結構64
3.1 語句64
3.1.1 簡單語句64
3.1.2 復合語句66
3.1.3 注釋67
3.1.4 語句的寫法68
3.2 輸入與輸出69
3.2.1 字符輸入與輸出69
3.2.2 格式化輸出71
3.2.3 格式化輸入76
3.3 程序順序結構79
3.3.1 順序執行79
3.3.2 跳轉執行79
3.4 程序選擇結構80
3.4.1 if語句80
3.4.2 switch語句84
3.4.3 選擇結構的嵌套86
3.4.4 選擇結構程序舉例90
3.5 程序循環結構92
3.5.1 while語句92
3.5.2 do語句94
3.5.3 for語句96
3.5.4 break語句97
3.5.5 continue語句98
3.5.6 循環結構的嵌套99
3.5.7 循環結構程序舉例99
習題103
第4章 函數106
4.1 函數定義106
4.1.1 函數定義的一般形式106
4.1.2 函數返回109
4.2 函數參數110
4.2.1 形式參數110
4.2.2 實際參數111
4.2.3 參數傳遞機制111
4.2.4 函數調用棧112
4.2.5 const參數114
4.2.6 可變參數函數114
4.3 函數原型與調用116
4.3.1 函數聲明和函數原型116
4.3.2 庫函數的調用方法119
4.3.3 標準庫函數120
4.4 內聯函數124
4.5 函數調用形式125
4.5.1 嵌套調用125
4.5.2 遞歸調用128
4.6 作用域和生命期130
4.6.1 局部變量130
4.6.2 全局變量131
4.6.3 作用域132
4.6.4 程序映像和內存布局135
4.6.5 生命期138
4.7 對象初始化141
4.8 聲明與定義143
4.9 變量修飾小結145
4.10 程序組織結構146
4.10.1 內部函數146
4.10.2 外部函數146
4.10.3 多文件結構147
4.10.4 頭文件與工程文件148
4.10.5 提高編譯速度149
4.11 函數應用程序舉例151
習題154
第5章 預處理命令156
5.1 宏定義156
5.1.1 不帶參數的宏定義157
5.1.2 帶參數的宏定義159
5.1.3 #和##預處理運算163
5.1.4 預定義宏163
5.2 文件包含164
5.3 條件編譯166
5.3.1 #define定義條件166
5.3.2 #ifdef、#ifndef166
5.3.3 #if-#elif167
5.4 其他命令168
習題169
第6章 數組171
6.1 一維數組的定義和引用171
6.1.1 一維數組的定義171
6.1.2 一維數組的初始化173
6.1.3 一維數組的引用173
6.2 多維數組的定義和引用175
6.2.1 多維數組的定義175
6.2.2 多維數組的初始化177
6.2.3 多維數組的引用178
6.3 數組與函數181
6.3.1 數組作為函數的參數181
6.3.2 數組參數的傳遞機制182
6.4 字符串185
6.4.1 字符數組185
6.4.2 字符串187
6.4.3 字符串的輸入和輸出189
6.4.4 字符串數組190
6.4.5 字符串處理函數191
6.5 數組應用程序舉例196
習題206
第7章 指針208
7.1 指針與指針變量208
7.1.1 地址和指針的概念208
7.1.2 指針變量209
7.2 指針的使用及運算211
7.2.1 獲取對象的地址211
7.2.2 指針的間接訪問212
7.2.3 指針變量的初始化與賦值214
7.2.4 指針的有效性216
7.2.5 指針運算217
7.2.6 指針的const限定222
7.3 指針與數組224
7.3.1 指向一維數組元素的指針224
7.3.2 指向多維數組元素的指針228
7.3.3 數組指針232
7.3.4 指針數組234
7.3.5 指向指針的指針236
7.4 指針與字符串238
7.4.1 指向字符串的指針239
7.4.2 指針與字符數組的比較241
7.4.3 指向字符串數組的指針242
7.5 指針與函數244
7.5.1 指針作為函數參數244
7.5.2 函數返回指針值253
7.5.3 函數指針254
7.6 動態內存258
7.6.1 動態內存的概念258
7.6.2 動態內存的分配和釋放259
7.6.3 動態內存的應用260
7.7 帶參數的main函數264
習題266
第8章 自定義數據類型267
8.1 結構體類型267
8.2 結構體對象269
8.2.1 結構體對象的定義269
8.2.2 結構體對象的初始化272
8.2.3 結構體對象的使用272
8.3 結構體與數組274
8.3.1 結構體數組274
8.3.2 結構體數組成員274
8.4 結構體與指針275
8.4.1 指向結構體的指針275
8.4.2 指向結構體數組的指針277
8.4.3 結構體指針成員278
8.5 結構體與函數279
8.5.1 結構體對象作為函數參數279
8.5.2 結構體數組作為函數參數279
8.5.3 結構體指針作為函數參數280
8.5.4 函數返回結構體對象或指針280
8.6 共用體281
8.6.1 共用體概念及類型聲明281
8.6.2 共用體對象的定義282
8.6.3 共用體對象的使用282
8.6.4 結構體與共用體嵌套284
8.7 枚舉類型284
8.7.1 枚舉類型的聲明284
8.7.2 枚舉類型對象285
8.8 位域285
8.8.1 位域的聲明285
8.8.2 位域的使用287
8.9 用戶自定義類型288
習題291
第9章 鏈表293
9.1 鏈表概述293
9.1.1 鏈表的概念293
9.1.2 單鏈表與雙鏈表294
9.2 鏈表的創建295
9.2.1 創建單鏈表295
9.2.2 創建雙鏈表298
9.3 鏈表的運算299
9.3.1 鏈表的遍歷299
9.3.2 銷毀鏈表301
9.3.3 查找結點302
9.3.4 鏈表的逆序304
9.4 結點的插入與刪除304
9.4.1 單鏈表插入結點304
9.4.2 單鏈表刪除結點305
9.4.3 雙鏈表插入結點306
9.4.4 雙鏈表刪除結點307
習題308
第10章 文件311
10.1 文件概述311
10.1.1 文件系統311
10.1.2 流式文件312
10.1.3 文件指針312
10.2 文件打開與關閉313
10.2.1 文件打開313
10.2.2 文件關閉314
10.2.3 文件狀態315
10.2.4 文件緩沖316
10.3 文件讀寫操作317
10.3.1 文件讀寫操作的基本形式317
10.3.2 讀寫字符數據317
10.3.3 讀寫字符串數據318
10.3.4 讀寫格式數據319
10.3.5 讀寫數據塊321
10.4 文件定位324
習題325
第11章 算法327
11.1 算法基本概念327
11.1.1 什么是算法327
11.1.2 算法基本要素327
11.1.3 算法求解過程328
11.2 算法分析329
11.2.1 時間復雜度329
11.2.2 空間復雜度332
11.3 常用算法332
11.3.1 分治法332
11.3.2 動態規劃335
11.3.3 貪心算法338
11.3.4 回溯法341
習題343
第12章 數據結構345
12.1 數據結構基本概念345
12.1.1 什么是數據結構345
12.1.2 邏輯結構與存儲結構346
12.1.3 數據結構與數據類型346
12.2 線性表347
12.2.1 線性表的基本概念347
12.2.2 線性順序表及其運算350
12.2.3 線性鏈式表及其運算355
12.3 棧和隊列355
12.3.1 棧的定義355
12.3.2 棧的順序存儲及基本運算356
12.3.3 棧的鏈式存儲及基本運算358
12.3.4 隊列的定義358
12.3.5 隊列的順序存儲及基本運算359
12.3.6 隊列的鏈式存儲及基本運算361
12.4 樹和二叉樹361
12.4.1 樹的基本概念361
12.4.2 二叉樹及其基本性質364
12.4.3 二叉樹的存儲結構367
12.4.4 二叉樹的遍歷368
習題370
第13章 高級編程技術372
13.1 配置開發環境372
13.1.1 開發環境的路徑參數372
13.1.2 開發環境的路徑設置373
13.1.3 開發環境的配置375
13.1.4 函數庫的包含和連接376
13.1.5 函數庫配置舉例378
13.2 界面編程381
13.2.1 Windows編程的基本概念381
13.2.2 數據定義與數據類型382
13.2.3 消息與消息循環385
13.2.4 資源與資源文件387
13.2.5 Windows應用程序結構396
13.2.6 Windows編程框架402
13.2.7 圖形輸出409
13.2.8 事件處理425
13.2.9 控件與對話框434
13.3 圖形編程441
13.3.1 圖形編程概述441
13.3.2 OpenGL簡介442
13.3.3 GLUT編程模式444
13.3.4 Win32編程模式449
13.4 多媒體編程456
13.4.1 MCI編程456
13.4.2 MCIWnd編程462
13.4.3 MMAPI編程467
13.5 網絡編程472
13.5.1 Winsock簡介472
13.5.2 Winsock編程473
13.5.3 TCP編程模式476
13.5.4 UDP編程模式480
13.6 數據庫編程483
13.6.1 數據庫編程概述483
13.6.2 ODBC簡介484
13.6.3 ODBC編程487
13.6.4 數據庫編程舉例494
習題497
附錄A ASCII碼對照表499
附錄B C語言關鍵字500
附錄C C語言運算符及其優先級、結合性502
參考文獻504