天天看點

malloc與free使用方法避免記憶體洩漏

作為第一次在CSDN上寫部落格的菜鳥級新生,既不想污染大牛們的眼球,卻也想不斷提高自己,以為達到“仙”的級别,就先做随談錄記錄自己在C語言項目中所犯的錯誤;首先将自己看到的一個很有趣程式猿段子貼上:

有位負責維護的程式員半夜被叫起來,去修複一個出了問題的程式。但是程式的原作者已經離職,沒有辦法聯系上他。這個程式員從未接觸過這個程式。在仔細檢查所有的說明後,他隻發現了一條注釋,如下:

MOV AX 723h ;R.I.P.L.V.B.
           

這個維護程式員通宵研究這個程式,還是對注釋百思不得其解。雖然最後他還是把程式的問題成功排除了,但這個神秘的注釋讓他耿耿于懷。說明一點:彙程式設計式的注釋是以分号開頭。幾個月後,這名程式員在一個會議上遇到了注釋的原作者。經過請教後,才明白這條注釋的意思:安息吧,路德維希.凡.貝多芬(Rest in peace, Ludwig Van Neethoven)。貝多芬于1827 年逝世,而1827 的十六進制正是723。不得不佩服這些大牛們的思維風暴,與對大師的愐懷性敬仰。下面切入正題:

曾有人問資料庫的維護人員”心裡有沒有點B樹?“,就如同對于C/C++程式員來說”心裡有沒有點分段?“一樣;那麼記憶體分段中有個動态區也就是堆區(heap),需要我們自己去維護,所用到的函數調用為:malloc(new),free(delete),很多時候我們對程式的段錯誤而感到很崩潰,而段錯誤的産生往往是因為我們對記憶體的非法通路,段錯誤的産生往往有四個原因如下:

1.空指針操作  p = NULL ;  *p = 123;現象:直接在本行報錯,在驅動移植時這種錯誤往往也會導緻驅動加載時報錯;

2.野指針操作  int *p;   *p = 250;

    現象:在本行報錯機率較大 

3.指針指向空間已經釋放 (其實操作已釋放的指針也屬于對野指針操作的一種)

    現在:如果記憶體沒有被收回 則不報錯 但是有隐患

4.數組越界    int  data[8];   data[8] = 10;  data[-1] = 666;  data[i++] 

    現在:1. 在目前位置報錯

         2.在return 位置報錯

         3. 在上一層函數的return 位置報錯 

而這些段錯誤在我們進行堆區申請與釋放時很容易發生,故将申請堆區的流程進行梳理如下:

  • 堆區空間申請
void *malloc(size_t size);
           
  • 申請記憶體清零(兩個函數任選其一即可)
void *memset(void *s, int c, size_t n); 
      void bzero(void *s, size_t n);  
           
  • 對所申請的記憶體初始化

釋放記憶體空間

void free(void *ptr);  
           

另外還有一個問題:用malloc 函數申請0 位元組記憶體會傳回NULL 指針嗎?可以測試一下,也可以去查找關于malloc 函數的說明文檔。申請0 位元組記憶體,函數并不傳回NULL,而是傳回一個正常的記憶體位址。但是你卻無法使用這塊大小為0 的記憶體。好比尺子上的某個刻度,刻度本身并沒有長度,隻有某兩個刻度一起才能量出長度。對于這一點一定要小心,因為這時候if(NULL != p)語句校驗将不起作用。

free 函數看上去挺狠的,但它到底作了什麼呢?其實它就做了一件事:斬斷指針變量與這塊記憶體的關系。比如上面的例子,我們可以說malloc 函數配置設定的記憶體塊是屬于p 的,因為我們對這塊記憶體的通路都需要通過p 來進行。free 函數就是把這塊記憶體和p 之間的所有關

系斬斷。從此p 和那塊記憶體之間再無瓜葛。至于指針變量p 本身儲存的位址并沒有改變,但是它對這個位址處的那塊記憶體卻已經沒有所有權了(如讀寫權限)。那塊被釋放的記憶體裡面儲存的值也沒有改變,隻是再也沒有辦法使用了。另外務必注意一個malloc對應一個free;也就是說,在程式中malloc 的使用次數一定要和free 相等,否則必有錯誤。這種錯誤主要發生在循環使用malloc 函數時,往往把malloc 和free 次數弄錯了。

最後我們必須注意一點:既然使用free 函數之後指針變量p 本身儲存的位址并沒有改變,那我們就需要重新把p的值變為NULL:否則後續使用p時必定出現段錯誤,因為此時已經釋放的p其實是野指針,也有書叫“懸垂指針”。這是很危險的,而且也是經常出錯的地方。是以一定要記住一條:free 完之後,一定要給指針置NULL。