C語(yǔ)言難點(diǎn)揭秘[1]

字號(hào):

正確的內(nèi)存管理的重要性
    存在內(nèi)存錯(cuò)誤的 C 和 C++ 程序會(huì)導(dǎo)致各種問題。如果它們泄漏內(nèi)存,則運(yùn)行速度會(huì)逐漸變慢,并最終停止運(yùn)行;如果覆蓋內(nèi)存,則會(huì)變得非常脆弱,很容易受到惡意用戶的攻擊。從 1988 年的莫里斯蠕蟲 攻擊到有關(guān) Flash Player 和其他關(guān)鍵的零售級(jí)程序的最新安全警報(bào)都與緩沖區(qū)溢出有關(guān):“大多數(shù)計(jì)算機(jī)安全漏洞都是緩沖區(qū)溢出”,Rodney Bates 在 2004 年寫道。
    在可以使用 C 或 C++ 的地方,也廣泛支持使用其他許多通用語(yǔ)言(如 Java™、Ruby、Haskell、C#、Perl、Smalltalk 等),每種語(yǔ)言都有眾多的愛好者和各自的優(yōu)點(diǎn)。但是,從計(jì)算角度來(lái)看,每種編程語(yǔ)言優(yōu)于 C 或 C++ 的主要優(yōu)點(diǎn)都與便于內(nèi)存管理密切相關(guān)。與內(nèi)存相關(guān)的編程是如此重要,而在實(shí)踐中正確應(yīng)用又是如此困難,以致于它支配著面向?qū)ο缶幊陶Z(yǔ)言、功能性編程語(yǔ)言、高級(jí)編程語(yǔ)言、聲明性編程語(yǔ)言和另外一些編程語(yǔ)言的所有其他變量或理論。
    與少數(shù)其他類型的常見錯(cuò)誤一樣,內(nèi)存錯(cuò)誤還是一種隱性危害:它們很難再現(xiàn),癥狀通常不能在相應(yīng)的源代碼中找到。例如,無(wú)論何時(shí)何地發(fā)生內(nèi)存泄漏,都可能表現(xiàn)為應(yīng)用程序完全無(wú)法接受,同時(shí)內(nèi)存泄漏不是顯而易見。
    因此,出于所有這些原因,需要特別關(guān)注 C 和 C++ 編程的內(nèi)存問題。讓我們看一看如何解決這些問題,先不談是哪種語(yǔ)言。
    內(nèi)存錯(cuò)誤的類別
    首先,不要失去信心。有很多辦法可以對(duì)付內(nèi)存問題。我們先列出所有可能存在的實(shí)際問題:
    內(nèi)存泄漏
    錯(cuò)誤分配,包括大量增加 free() 釋放的內(nèi)存和未初始化的引用
    懸空指針
    數(shù)組邊界違規(guī)
    這是所有類型。即使遷移到 C++ 面向?qū)ο蟮恼Z(yǔ)言,這些類型也不會(huì)有明顯變化;無(wú)論數(shù)據(jù)是簡(jiǎn)單類型還是 C 語(yǔ)言的 struct 或 C++ 的類,C 和 C++ 中內(nèi)存管理和引用的模型在原理上都是相同的。以下內(nèi)容絕大部分是“純 C”語(yǔ)言,對(duì)于擴(kuò)展到 C++ 主要留作練習(xí)使用。
    內(nèi)存泄漏
    在分配資源時(shí)會(huì)發(fā)生內(nèi)存泄漏,但是它從不回收。下面是一個(gè)可能出錯(cuò)的模型(請(qǐng)參見清單 1):
    清單 1. 簡(jiǎn)單的潛在堆內(nèi)存丟失和緩沖區(qū)覆蓋
     void f1(char *explanation)
     {
     char p1;
     p1 = malloc(100);
     (void) sprintf(p1,
     "The f1 error occurred because of '%s'.",
     explanation);
     local_log(p1);
     }
    您看到問題了嗎?除非 local_log() 對(duì) free() 釋放的內(nèi)存具有不尋常的響應(yīng)能力,否則每次對(duì) f1 的調(diào)用都會(huì)泄漏 100 字節(jié)。在記憶棒增量分發(fā)數(shù)兆字節(jié)內(nèi)存時(shí),一次泄漏是微不足道的,但是連續(xù)操作數(shù)小時(shí)后,即使如此小的泄漏也會(huì)削弱應(yīng)用程序。
    在實(shí)際的 C 和 C++ 編程中,這不足以影響您對(duì) malloc() 或 new 的使用,本部分開頭的句子提到了“資源”不是僅指“內(nèi)存”,因?yàn)檫€有類似以下內(nèi)容的示例(請(qǐng)參見清單 2)。FILE 句柄可能與內(nèi)存塊不同,但是必須對(duì)它們給予同等關(guān)注