天天看點

《C語言程式設計進階教程》一導讀

《C語言程式設計進階教程》一導讀

為什麼要寫這本書

本文講的是<b>C語言程式設計進階教程一導讀</b>,市面上有成百上千種關于程式設計的書籍,其中有很多都是關于C語言程式設計的,那麼為什麼我還要寫這本書呢?為什麼建議你花時間讀它呢?這本書跟其他書有什麼不同呢?跟很多作者一樣,我寫這本書是因為我覺得有必要,覺得這本書中的方法比其他書中的更好。

我将現在已有的關于程式設計的書分為兩類:入門和進階。入門類書是給初學者寫的,一般都假設讀者沒有程式設計基礎,是以主要是介紹基本的概念。通常以“Hello World!”程式開始,也就是将“Hello World!”輸出到電腦螢幕的程式。這種類型的書主要是一步步地介紹語言特點,包括關鍵詞、資料類型、控制結構、字元串、檔案操作等,而這些書一般都有一個特點:程式很短,一般是1~2頁。這很奏效,因為短程式有助于解釋程式設計語言的新概念。如果把學程式設計語言比作學自然語言,如英語、漢語、法語、韓語等,這些書就相當于教導如何造句和撰寫短段落。

第二類書是寫給有程式開發經驗的讀者的。這些書主要介紹解決現實中的問題的程式,比如關于電腦遊戲或者圖像。而這類書的例子一般很長,有些甚至幾千行代碼,是以不會全部印在書本上。書中隻會解釋程式的其中一部分,而源程式一般儲存在CD或者某個網址上。這類書一般不會再介紹如何程式設計,而是大多專注于解決特定問題的算法研究,有時包括算法性能的詳細資訊。讀者不可能再找到類似于“Hello World!”這樣的例子。再比作自然語言的例子,這類書就是在教導如何撰寫可能超過20頁的短篇小說。

問題是,從寫一個段落到寫一篇小說,這種跨越太難了。

一本針對中級程式設計能力的學生的書

市面上很少有針對中級程式設計能力學生的書籍。這些學生往往已經掌握了程式設計的基本知識,在看到if或者while時不會茫然,知道如何建立函數和調用函數,有能力編寫幾十上百行的短代碼,卻不知道如何處理上千行的程式。他們經常會犯錯誤,因為大多數入門級的書籍隻教導如何編寫正确的程式,卻不會教導避免常見的錯誤。他們往往對大多數的概念和那些可以幫助提高程式設計能力的工具都不太熟悉,他們需要這樣一個台階:可以幫助他們從有能力編寫短代碼到有能力編寫解決現實問題的程式。

現在入門和進階的空檔已經被資料結構和算法的書籍填充了一部分,這類圖書一般提供實作資料結構或算法的完整例子。然而這并不是最合适的解決方法,這類圖書緻力于介紹資料結構和算法,卻罕有提供幫助讀者編寫正确代碼的資訊。事實上,它們大多隻提供程式,而很少解釋。它們往往不解釋程式設計概念,比如函數需要一個指針作為實參的原因或者深拷貝與淺拷貝之間的差異等。是以,讀者隻能自學這些程式設計技巧。

為了迎合這個需求,我寫下這本針對中級程式設計能力的學生的書,本書适合作為學習程式設計的第二本教材。

避免出錯和調試的重點

我們可以看到有很多關于如何程式設計的書籍,卻很少關于開發軟體的書籍。開發軟體不是簡單地輸入代碼,它需要更多的知識和技能。為了彌補這種不足,最好就是去研究什麼是對的、什麼是錯的。隻解釋如何編寫正确的程式是不夠的,還需要解釋常見的錯誤并将它們與正确的程式進行對比。

一次疏忽可能使程式運作出乎意料,甚至是某些情況下運作正确而另一些情況下出錯。這種類型的錯誤往往很難發現,更别說更正了。本書将介紹一些常見的錯誤以教導讀者如何避免這些錯誤。調試過程在大多數書中都不會涉及,罕有書籍會提到“調試器”這個詞,以至于有些讀者都不知道這類工具的存在。學會如何使用調試器一般不超過30分鐘,這可以幫助程式員節省很多時間。關于如何使用調試器和調試政策的書籍則更少了。

程式設計和離散數學

程式設計和離散數學是計算機科學中的兩個重要學科,然而,大多數書籍都将這兩個主題分開,是以很少會在程式設計的書籍中看到數學公式,同樣也很難在離散數學中看到代碼。在本書中,這兩個主題緊密結合,我相信讀者可以從中學到更多的知識。

為什麼本書使用C語言?

C語言誕生于20世紀60年代後期和20世紀70年代早期。在C語言發明之後,很多語言也相繼出現,這些語言也深受C語言的影響。除了它的曆史影響之外,C語言的簡單易用也保證了它在幾乎所有現代化平台中的重要地位。與許多作業系統一樣,Linux是就用C語言編寫的,Android基本都是用Java編寫的但仍有叫作JNI(Java Native Interface,Java本地接口)的C語言接口。大多數計算機語言都可以與C語言進行通信或通過C語言進行通信,事實上這對一種程式設計語言而言是有用的,因為大多數作業系統接口都使用C語言。當一個全新的系統被設計出來,C語言通常是第一種(很多情況下是唯一一種)被系統支援的程式設計語言。

對于具有中級程式設計能力的學生來說,C語言是一個很好的選擇,因為學習C語言需要了解很多計算機概念。langpop.com網站對比了程式設計語言的受歡迎程度,得出C語言是最受歡迎的語言,緊接着是Java。IEEE Spectrum中的一個報告将程式設計語言進行排行,主要考慮四類軟體:移動應用、企業軟體、嵌入式系統和網頁。其中嵌入式系統中最受歡迎的就是C語言。四種類型都考慮時,前五名程式設計語言如下所示:

Java(100%)

C(99.3%)

C++(95.5%)

Python(93.4%)

C#(92.4%)

可以發現,基于C的程式設計語言(C、C++、C#)占據了前五席的三席。而Java是受C++影響的。

為什麼需要讀這本書?

如果你是計算機科學、計算機工程或者電子工程專業的學生,那麼就絕對應該讀本書。本書包含了很多基本概念,這些概念對于了解計算機中程式的運作方式十分重要。如果你是工程、科學、數學或者技術專業的學生,在學習工作中就很有可能需要用到計算機,而閱讀本書将會有很大幫助。即便你不是上述專業的學生,仍然可以在本書中學到很多有用的概念(比如遞歸)。

作者、審稿人及封面設計師

作者簡介

Yung-Hsiang Lu 是美國印第安納州西拉法葉普渡大學電子與計算機工程學院的副教授。他是美國計算機協會(ACM)的傑出科學家和演說家。2011年8~12月,曾是新加坡國立大學計算機科學系的客座副教授。他在美國加利福尼亞州斯坦福大學電子工程系取得博士

學位。

審稿人簡介

Aaron Michaux是美國印第安納州西拉法葉普渡大學電子與計算機工程學院的一名研究所學生。他在澳洲昆士蘭科技大學取得計算機科學學士學位,在加拿大新布倫瑞克聖托馬斯大學獲得心理學學士學位。Aaron在重新回到學校攻讀博士學位之前已經作為專業程式員工作了10年。他的研究方向主要圍繞計算機視覺和人類視覺感覺。

Pranav Marla是美國印第安納州西拉法葉普渡大學電子與計算機工程學院的一名大學生。他主修的專業是計算機科學。在計算機工程、心理學和哲學上也稍有涉獵。他希望可以專攻機器學習和人工智能。

封面設計師簡介

本書封面是由Kyong Jo Yoon描繪的。他是一名南韓畫家,經常在自然場景中加入英雄人物。他是南韓美術協會的一名顧問,他的作品在美國伊利諾伊州芝加哥市的安内森美術館中展出。

軟體開發中的規則

如果由于軟體錯誤,銀行每天将你的錢減少0.1%,你會滿意嗎?你能接受每個月都少走40分鐘的手表嗎?這兩種情況都是“成功了99.9%”,但卻都讓人無法接受。計算機現在用在很多應用程式中,有些甚至會影響人類的安全。即使你編寫的程式在99.9%的時間裡都可以正确地運作,那也有可能會在剩餘的0.1%的時間裡危害人類的生命。這是絕對讓人無法接受的,這是一個失敗的程式。是以,99.9%的成功就是失敗。

如果你住在加州的帕薩迪納,現在想去紐約,你會走哪條路呢?也許你會去洛杉矶機場,然後坐飛機去紐約。但是紐約在帕薩迪納的東邊,而機場在帕薩迪納的西邊。你為什麼不直接開車去東邊呢?你為什麼要繞路去機場呢?如果你直接開車去東邊,而不是去機場排隊的話,你就離紐約越來越近了啊。答案很簡單:相對于汽車來講,飛機這一交通工具更适合長途旅行。在程式開發中,有許多用以管理大型軟體的開發工具,你需要學習這些工具。沒錯,學習使用工具會消耗一些時間,但是如果你使用不合适的工具或者不使用工具的話,将浪費更多的時間。花些時間學習使用程式設計工具将在軟體開發和調試時節省大量時間。

盡管經過了數十年的努力,現在的計算機依然沒有達到智能化的水準。計算機無法猜測你的想法。如果你寫的程式讓計算機去做一件錯事,那麼計算機就會跟随指令去做。如果你的程式是錯的,那就是你的責任。計算機無法猜測你的想法。在很多例子中,計算機程式中一個微小的錯誤就可以造成巨大的财産損失,甚至危及人類的生命。缺少一個分号“;”或者用“,”取代“. ”,程式将無法執行。計算機程式不能容忍任何微小的錯誤。

通過測試方案并不能保證程式的正确性。測試隻能得出一個程式有錯誤的結論但不能表明一個程式是正确的。為什麼呢?測試方案能覆寫所有可能的情景嗎?覆寫全部情景是非常困難的,而且在很多情況下是不可能的。因為測試方案很難檢測特殊行為,是以一些問題可能會隐藏在你的程式中。

産生正确的輸出并不意味着程式是正确的。你會認為一架已經安全起飛并着陸的飛機是安全的嗎?如果飛機在漏油,你會在登機前要求航空公司維修飛機嗎?如果航空公司回複:“之前沒有人受傷,說明這架飛機是安全的。”你會接受航空公司的回應嗎?如果司機闖紅燈而沒出事故的話,是否意味着闖紅燈是安全的呢?一個可以産生正确輸出的程式就像是一架安全着陸的飛機。可能有很多問題隐藏在安全的表面之下。很多工具可以檢測人類隐藏的健康問題,比如X–射線,核磁共振以及超音波掃描。我們也需要工具來檢測出隐藏在電腦程式中的問題。即使程式可以産生正确的輸出,我們也要對它們進行修改。

你必須假設程式會出問題,并開發出檢測和改正問題的政策。在寫程式時,應該每次隻專注于一小部分。在仔細檢查并確定沒有問題之後再進行下一部分。對于大多數程式,你需要為了測試這些小的子產品而編寫額外的程式。雖然這些測試代碼并不包含在最終的程式中,但是編寫測試程式可以節省大量時間。有時,測試代碼可能會比程式本身還要多。我自己的經驗建議1:3的比例:最終程式中的1行代碼,需要3行測試代碼。

沒有什麼工具可以取代一個清醒的大腦。工具可以提供一些幫助,但是對概念清晰深刻的了解才是最重要的。如果你想成為一名優秀的程式員,那麼你需要完全了解每一個細節。不要指望工具可以替你思考:它們做不到。

源代碼

本書中所有的程式都可以從github.com上擷取。請使用下面的指令擷取檔案:

…………………………………………

$是Linux終端的shell提示符

<a href="https://yq.aliyun.com/articles/214042">1.1 編譯</a>

<a href="https://yq.aliyun.com/articles/214053">1.2 重定向輸出</a>

<a href="https://yq.aliyun.com/articles/214073">2.1 值和位址</a>

<a href="https://yq.aliyun.com/articles/214088">2.2 棧</a>

<a href="https://yq.aliyun.com/articles/214121">2.3 調用棧</a>

<a href="https://yq.aliyun.com/articles/214134">2.3.2 函數實參</a>

<a href="https://yq.aliyun.com/articles/214139">2.3.3 局部變量</a>

<a href="https://yq.aliyun.com/articles/214148">2.3.4 值位址</a>

<a href="https://yq.aliyun.com/articles/214153">2.3.5 數組</a>

<a href="https://yq.aliyun.com/articles/214157">2.3.6 擷取位址</a>

<a href="https://yq.aliyun.com/articles/214166">2.4 可見度</a>

<a href="https://yq.aliyun.com/articles/214170">2.5 習題</a>

<a href="https://yq.aliyun.com/articles/214175">2.5.1 繪制調用棧I</a>

<a href="https://yq.aliyun.com/articles/214180">2.5.2 繪制調用棧II</a>

<a href="https://yq.aliyun.com/articles/214188">2.6.1 繪制調用棧I</a>

<a href="https://yq.aliyun.com/articles/214193">2.6.2 繪制調用棧II</a>

<a href="https://yq.aliyun.com/articles/214406">2.7 在DDD(指令行調試程式)上檢測調用棧</a>

<a href="https://yq.aliyun.com/articles/214412">第3章 預防、檢測及消除bug</a>

<a href="https://yq.aliyun.com/articles/214418">3.1.1 程式設計前</a>

<a href="https://yq.aliyun.com/articles/214423">3.1.2 程式設計中</a>

<a href="https://yq.aliyun.com/articles/214431">3.1.3 程式設計後</a>

<a href="https://yq.aliyun.com/articles/214434">3.2 常見錯誤</a>

<a href="https://yq.aliyun.com/articles/214439">3.2.1 未初始化變量</a>

<a href="https://yq.aliyun.com/articles/214443">3.2.2 錯誤數組下标</a>

<a href="https://yq.aliyun.com/articles/214453">3.3 後執行式和互動式調試</a>

<a href="https://yq.aliyun.com/articles/214458">3.4 生産代碼與測試代碼分離</a>

原文标題:C語言程式設計進階教程一導讀