日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C 的內(nèi)存管理

 閑來看看 2013-01-30

C++的內(nèi)存管理

分類: C/C++10691人閱讀評論(95)收藏舉報

目錄(?)[+]

這篇文章是我在學習高質(zhì)量C++/C編程指南中的第7章"內(nèi)存管理"后的一篇筆記,之前我也寫過相關(guān)的文章指針以及內(nèi)存分配,但我感覺那篇還不是很好,這篇我很把它更完善一些

一.內(nèi)存的常見分配方式

  1. 從靜態(tài)區(qū)分配,一般是全局變量和static類型變量

  2.從棧區(qū)分配內(nèi)存,一般是局部的變量,會隨著所在函數(shù)的結(jié)束而自動釋放

  3.從堆中分配,一般是使用手動分配,使用malloc()函數(shù)和new來申請任意大小空間,不過要手動釋放空間,相應的使用free()函數(shù)和delete釋放,

    如果不釋放該空間,而且指向該空間的指針指向了別的空間.則該空間就無法釋放,造成內(nèi)存泄露,造成了內(nèi)存浪費

二.內(nèi)存的使用規(guī)則

  1.在使用malloc()或new申請空間時,要檢查有沒有分配空間成功,判斷方法是判斷指針是否為NULL,如申請一塊很大的內(nèi)存而沒有這么大的內(nèi)存則分配內(nèi)存會失敗

  2.申請成功后最好是將該內(nèi)存清空,使用memset()后ZeroMemory()清空,不然存在垃圾而造成有時候輸出很大亂碼

  3.不要忘記為數(shù)組和動態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。(這句話不太理解)

  4.要防止數(shù)組或指針內(nèi)存越界,

  5.申請內(nèi)存成功后,使用結(jié)束后要釋放,系統(tǒng)不會自動釋放手動分配的內(nèi)存

  6.內(nèi)存釋放后,指針還是指向那塊地址,不過這指針已經(jīng)是"野指針"了,所以釋放內(nèi)存后指針要指向NULL,不然很危險,容易出錯,if()對野指針的判斷不起作用

三.指針和數(shù)組

  1. 數(shù)組里的數(shù)據(jù)可以單個修改,但指針的不行,如我的例子,char str[] = "hello",數(shù)組的大小有6個字符(注意\0),可以通過str[0] = 'X'修改了的個字符,而指針

char *p = "Word",p是指向了一串常量的字符串,常量字符串是不可修改的,如 p[0] = 'X',編譯器編譯時不會保存,但執(zhí)行時會出錯

 

 

   2.內(nèi)容的復制與比較

   內(nèi)容的復制要使用strcpy()函數(shù),不要使用賦值符"=",內(nèi)容的比較也是不要使用比較符號"<,>,==",使用strcmp()函數(shù)

  1. // 數(shù)組…  
  2.   
  3.     char a[] = "hello";  
  4.   
  5.     char b[10];  
  6.   
  7.     strcpy(b, a);           // 不能用   b = a;  
  8.   
  9.     if(strcmp(b, a) == 0)   // 不能用  if (b == a)  

  1. // 指針…  
  2.   
  3.    int len = strlen(a);  
  4.   
  5.    char *p = (char *)malloc(sizeof(char)*(len+1));  
  6.   
  7.    strcpy(p,a);            // 不要用 p = a;  
  8.   
  9.    if(strcmp(p, a) == 0)   // 不要用 if (p == a)  

    3,計算空間的大小

 對數(shù)組的計算是使用sizeof()函數(shù),該函數(shù)會按照內(nèi)存對齊的方式4的倍數(shù)計算,而指針的空間大小沒法計算,只能記住在申請空間時的空間大小

注意當數(shù)組作為函數(shù)的參數(shù)進行傳遞時,該數(shù)組自動退化為同類型的指針,不論數(shù)組a的容量是多少,sizeof(a)始終等于sizeof(char *)

 

 

  1. void Func(char a[100])  
  2.   
  3.     {  
  4.   
  5.         cout<< sizeof(a) << endl;   // 4字節(jié)而不是100字節(jié)  
  6.   
  7. }  


 

四.指針的內(nèi)存的傳遞

如果函數(shù)的參數(shù)是指針,則不要使用該參數(shù)來申請內(nèi)存空間,這樣沒有實際的用處,而且這樣當函數(shù)結(jié)束時還得不到釋放內(nèi)存而造成內(nèi)存泄露

 

     這個問題可以使用"指針的指針"的方法可以解決,不然使用返回指針地址的辦法,先看一下使用 "指針的指針"方法,

還可以考慮一下引用

 

 

使用返回內(nèi)存地址的方法

 

 使用返回的方式傳遞內(nèi)存地址容易出錯的地方在于放回"棧內(nèi)存"的指針,當GetMemory()函數(shù)結(jié)束時棧內(nèi)存也被釋放,

 

 

 像這個代碼

  1. char *GetString2(void)  
  2.   
  3. {  
  4.   
  5.     char *p = "hello world";  
  6.   
  7.     return p;  
  8.   
  9. }  
  10.    
  11. void Test5(void)  
  12.   
  13. {  
  14.   
  15.     char *str = NULL;  
  16.   
  17.     str = GetString2();  
  18.   
  19.     cout<< str << endl;  
  20.   
  21. }  
  22.    

函數(shù)Test5運行雖然不會出錯,但是函數(shù)GetString2的設(shè)計概念卻是錯誤的。因為GetString2內(nèi)的“hello world”是常量字符串,位于靜態(tài)存儲區(qū),

它在程序生命期內(nèi)恒定不變。無論什么時候調(diào)用GetString2,它返回的始終是同一個“只讀”的內(nèi)存塊。

 

五.動態(tài)內(nèi)存釋放問題與野指針

   1. 當我們使用free()和delete釋放一塊內(nèi)存時,指針還是指向原來的地址,不過這時候的指針時野指針,

可以驗證一下.這圖是我調(diào)試到if()語句時的情況,p還沒有指向NULL,只是釋放了p指向的空間了

 

 

 

執(zhí)行的結(jié)果可以看看...

 

 

所以有這樣的一些特征:

1.指針銷毀了,并不表示所指的空間也得到了釋放 :內(nèi)存泄露

2.內(nèi)存被釋放了,并不表示指針也被銷毀了或指向NULL :野指針

 

六.malloc()/free()與new/delete的區(qū)別(摘抄原文)

malloc與free是C++/C語言的標準庫函數(shù),new/delete是C++的運算符。它們都可用于申請動態(tài)內(nèi)存和釋放內(nèi)存。對于非內(nèi)部數(shù)據(jù)類型的對象而言,

光用maloc/free無法滿足動態(tài)對象的要求。對象在創(chuàng)建的同時要自動執(zhí)行構(gòu)造函數(shù),對象在消亡之前要自動執(zhí)行析構(gòu)函數(shù)。由于malloc/free是庫函

數(shù)而不是運算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強加于malloc/free。

因此C++語言需要一個能完成動態(tài)內(nèi)存分配和初始化工作的運算符new,以及一個能完成清理與釋放內(nèi)存工作的運算符delete。注意new/delete不是庫函數(shù)。

我們先看一看malloc/free和new/delete如何實現(xiàn)對象的動態(tài)內(nèi)存管理,看代碼

  1. class Obj  
  2.   
  3. {  
  4.   
  5. public :  
  6.   
  7.         Obj(void){ cout << “Initialization” << endl; }  
  8.   
  9.         ~Obj(void){ cout << “Destroy” << endl; }  
  10.   
  11.         void    Initialize(void){ cout << “Initialization” << endl; }  
  12.   
  13.         void    Destroy(void){ cout << “Destroy” << endl; }  
  14.   
  15. };  
  16.    
  17. void UseMallocFree(void)  
  18.   
  19. {  
  20.   
  21.     Obj  *a = (obj *)malloc(sizeof(obj));   // 申請動態(tài)內(nèi)存  
  22.   
  23.     a->Initialize();                        // 初始化  
  24.   
  25.     //…  
  26.   
  27.     a->Destroy();   // 清除工作  
  28.   
  29.     free(a);        // 釋放內(nèi)存  
  30.   
  31. }  
  32.    
  33. void UseNewDelete(void)  
  34.   
  35. {  
  36.   
  37.     Obj  *a = new Obj;  // 申請動態(tài)內(nèi)存并且初始化  
  38.   
  39.     //…  
  40.   
  41.     delete a;           // 清除并且釋放內(nèi)存  
  42.   
  43. }  
  44.    

       類Obj的函數(shù)Initialize模擬了構(gòu)造函數(shù)的功能,函數(shù)Destroy模擬了析構(gòu)函數(shù)的功能。函數(shù)UseMallocFree中,由于malloc/free不能執(zhí)行構(gòu)造函數(shù)與析構(gòu)函數(shù),必須調(diào)用成員函數(shù)Initialize和Destroy來完成初始化與清除工作。函數(shù)UseNewDelete則簡單得多。

       所以我們不要企圖用malloc/free來完成動態(tài)對象的內(nèi)存管理,應該用new/delete。由于內(nèi)部數(shù)據(jù)類型的“對象”沒有構(gòu)造與析構(gòu)的過程,對它們而言malloc/free和new/delete是等價的。

    既然new/delete的功能完全覆蓋了malloc/free,為什么C++不把malloc/free淘汰出局呢?這是因為C++程序經(jīng)常要調(diào)用C函數(shù),而C程序只能用malloc/free管理動態(tài)內(nèi)存。

如果用free釋放“new創(chuàng)建的動態(tài)對象”,那么該對象因無法執(zhí)行析構(gòu)函數(shù)而可能導致程序出錯。如果用delete釋放“malloc申請的動態(tài)內(nèi)存”,理論上講程序不會出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。

 

 七.如何處理內(nèi)存耗盡

   1.判斷指針是否為NULL,如果是則馬上用return語句終止本函數(shù)

   2.判斷指針是否為NULL,如果是則馬上用exit(1)終止整個程序的運行

   3.為new和malloc設(shè)置異常處理函數(shù)。例如Visual C++可以用_set_new_hander函數(shù)為new設(shè)置用戶自己定義的異常處理函數(shù),

      也可以讓malloc享用與new相同的異常處理函數(shù)

malloc()/free()和new/delete的使用要點網(wǎng)上有更詳細的說明

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多