<kbd id="daqct"></kbd>

  • <nav id="daqct"></nav>
    <wbr id="daqct"><pre id="daqct"></pre></wbr>
    <wbr id="daqct"></wbr>
    <form id="daqct"><th id="daqct"></th></form>
    更多課程 選擇中心

    C/C++培訓
    達內IT學院

    400-111-8989

    C與C++內存管理避坑指南

    • 發布:C++培訓
    • 來源:C++資訊
    • 時間:2020-12-24 15:17

    對于計算機程序處理而言,對內存的管理就像是對一片雷區的管理,管理的好,可以殺死一片一片的bug,管理的不好,將使你自己抓狂,程序漏洞百出,直至崩潰,據調查80%的程序崩潰都是內存的管理出現問題,有時候表面沒有問題,運行一段時間后問題就爆發了,所以對內存的管理非常重要,這里和大家一起總結討論下C/C++中關于內存管理的一些要點。

    內存分配方式有哪些?

    內存分配方式有三種:

    (1)從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static變量。

    (2)在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。

    (3)從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活,但問題也最多。

    常見的內存錯誤及其對策

    發生內存錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程序運行時才能捕捉到。而這些錯誤大多沒有明顯的癥狀,時隱時現,增加了改錯的難度。有時用戶怒氣沖沖地把你找來,程序卻沒有發生任何問題,你一走,錯誤又發作了,是不是要抓狂??項目開發時,客戶和項目一個勁的催,早點上線,來不及充分測試,初步測試沒問題就上線,運行一段時間就各種小bug,自己調試問題一下又找不到是不是很郁悶!!

    常見的內存錯誤及其對策如下:

    (1)內存分配未成功,卻使用了它。

    新手常犯這種錯誤,因為他們沒有意識到內存分配會不成功。常用解決辦法是,在使用內存之前檢查指針是否為NULL。如果指針p是函數的參數,那么在函數的入口處用assert(p!=NULL)進行檢查。如果是用malloc或new來申請內存,應該用if(p==NULL)或if(p!=NULL)進行防錯處理。

    (2)內存分配雖然成功,但是尚未初始化就引用它。

    犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為內存的缺省初值全為零,導致引用初值錯誤。

    int * p = NULL;

    p = (int*)malloc(sizeof(int));

    if (p == NULL)

    {

    /*...*/

    }

    /*初始化為0*/

    memset(p, 0, sizeof(int));

    內存的缺省初值究竟是什么并沒有統一的標準,盡管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式創建數組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。

    (3)內存分配成功并且已經初始化,但操作越過了內存的邊界。

    例如在使用數組時經常發生下標“多1”或者“少1”的操作,數組訪問越界在運行時,它的表現是不定的,有時似乎什么事也沒有,程序一直運行(當然,某些錯誤結果已造成);有時,則是程序一下子崩潰。特別是在for循環語句中,循環次數很容易搞錯,導致數組操作越界。

    char *ptr = (char *)malloc(10);

    char name[20] ;

    memcpy ( name,ptr,20); // Problem begins here

    int mark[100];

    ...

    //讓用戶輸入學生編號,設現實中學生編號由1開始:

    cout << "請輸入學生編號(在1~100之間):"

    int i;

    cin >> i;

    //輸出對應學生的考試成績:

    cout << info[i-1];

    (4)忘記了釋放內存,造成內存泄露。

    含有這種錯誤的函數每被調用一次就丟失一塊內存。剛開始時系統的內存充足,你看不到錯誤。終有一次程序突然死掉,系統出現提示:內存耗盡。

    動態內存的申請與釋放必須配對,程序中malloc與free的使用次數一定要相同,否則肯定有錯誤(new/delete同理)。

    class Object {

    private:

    void* data;

    const int size;

    const char id;

    public:

    Object(int sz, char c):size(sz), id(c){

    data = new char[size];

    cout << "Object() " << id << " size = " << size << endl;

    }

    ~Object(){

    cout << "~Object() " << id << endl;

    delete []data;

    }

    };

    以上代碼會在堆區瘋狂的動態分配內存空間,導致系統內存耗盡時自動調用set_new_handler參數列表中的函數,打印出ERROR:內存已耗盡!

    (5)釋放了內存卻繼續使用它。

    有三種情況:

    (1)程序中的對象調用關系過于復雜,實在難以搞清楚某個對象究竟是否已經釋放了內存,此時應該重新設計數據結構,從根本上解決對象管理的混亂局面。

    void GetMemory2(char **p, int num)

    {

    *p = (char *)malloc(sizeof(char) * num);

    }

    void Test2(void)

    {

    char *str = NULL;

    GetMemory2(&str, 100); // 注意參數是 &str,而不是str

    strcpy(str, "hello");

    cout<< str << endl;

    free(str);

    }

    問題出在函數GetMemory中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是 _p,編譯器使 _p = p。如果函數體內的程序修改了_p的內容,就導致參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。在本例中,_p申請了新的內存,只是把 _p所指的內存地址改變了,但是p絲毫未變。所以函數GetMemory并不能輸出任何東西。事實上,每執行一次GetMemory就會泄露一塊內存,因為沒有用free釋放內存。

    (2)函數的return語句寫錯了,注意不要返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。

    void port();

    void addr();

    int main ()

    {

    addr();

    port();

    }

    long *p ;

    void port()

    {

    long i, j ;

    j = 0;

    for ( i = 0 ; i < 10 ; i++ )

    {

    (*p)--;

    j++;

    }

    }

    void addr()

    {

    long k;

    k = 0;

    p = &k;

    }

    這里的問題出現在保存臨時變量的地址上。由于addr函數中的變量k在函數返回后就已經不存在了,但是在全局變量p中卻保存了它的地址。在下一個函數port中,試圖通過全局指針p訪問一個不存在的變量,而這個指針實際指向的卻是另一個臨時變量i,這就導致了死循環的發生。

    char *GetString2(void)

    {

    char *p = "hello world";

    return p;

    }

    void Test5(void)

    {

    char *str = NULL;

    str = GetString2();

    cout<< str << endl;

    }

    執行str = GetString語句后str不再是NULL指針,但是str的內容不是“hello world”而是垃圾。

    (3)使用free或delete釋放了內存后,沒有將指針設置為NULL。導致產生“野指針”。

    char *p = (char *) malloc(10);

    strcpy(p, “hello”);free(p); // p所指的內存被釋放,但是p所指的地址仍然不變…//忘記 釋放 strcpy(p, “world”); // 出錯

    char *p = (char *) malloc(10);

    strcpy(p, “hello”);

    free(p); // p所指的內存被釋放,但是p所指的地址仍然不變…

    if(p != NULL) // 雖然記得,但沒有起到防錯作用

    {

    strcpy(p, “world”); // 出錯

    }

    總結5條黃金規則

    【規則1】用malloc或new申請內存之后,應該立即檢查指針值是否為NULL。防止使用指針值為NULL的內存。

    【規則2】不要忘記為數組和動態內存賦初值。防止將未被初始化的內存作為右值使用。

    【規則3】避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。

    【規則4】動態內存的申請與釋放必須配對,防止內存泄漏。

    【規則5】用free或delete釋放了內存之后,立即將指針設置為NULL,防止產生“野指針”。

    文章來源:C語言與CPP編程,版權聲明:轉載文章來自公開網絡,版權歸作者本人所有,推送文章除非無法確認,我們都會注明作者和來源。如果出處有誤或侵犯到原作者權益,請與我們聯系刪除或授權事宜。

    預約申請免費試聽課

    填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

    上一篇:C/C++代碼規范注釋有哪些講究?
    下一篇:C語言宏定義的幾種使用方法

    C語言宏定義的幾種使用方法

    C與C++內存管理避坑指南

    C/C++代碼規范注釋有哪些講究?

    C語言中,全局變量濫用的后果竟如此嚴重?

    • 掃碼領取資料

      回復關鍵字:視頻資料

      免費領取 達內課程視頻學習資料

    • 視頻學習QQ群

      添加QQ群:1143617948

      免費領取達內課程視頻學習資料

    Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

    選擇城市和中心
    黑龍江省

    吉林省

    河北省

    湖南省

    貴州省

    云南省

    廣西省

    海南省

    欧美三级片,白洁外传,第四色播日韩AV第一页,啪啪免费观看大全av 百度 好搜 搜狗
    <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>