(轉)C語言malloc()與free()的使用


如何使用 malloc 函數


本文為轉載內容,原文地址請點擊

不要莫名其妙,其實上面這段小小的對話,就是malloc的使用過程。malloc是一個函數,專門用來從堆上分配內存。使用malloc函數需要幾個要求:

  • 內存分配給誰?
  • 分配多大內存?
  • 是否還有足夠內存分配?
  • 內存的將用來存儲什么格式的數據,即內存用來做什么?
  • 分配好的內存在哪里?

如果這五點都確定,那內存就能分配。下面先看malloc函數的原型:

(void *)malloc(int size)

看到了沒有,這里的返回類型是(void *),這是多巧妙的一個設計啊。

malloc函數的返回值是一個void類型的指針,參數為int類型數據,即申請分配的內存大小,單位是byte。內存分配成功之后,malloc函數返回這塊內存的首地址。你需要一個指針來接收這個地址。但是由於函數的返回值是void *類型的,所以必須強制轉換成你所接收的類型。也就是說,這塊內存將要用來存儲什么類型的數據。比如:

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

在堆上分配了100個字節內存,返回這塊內存的首地址,把地址強制轉換成char *類型后賦給char *類型的指針變量p。同時告訴我們這塊內存將用來存儲char類型的數據。也就是說你只能通過指針變量p來操作這塊內存。這塊內存本身並沒有名字,對它的訪問是匿名訪問
  

上面就是使用malloc函數成功分配一塊內存的過程。但是,每次你都能分配成功嗎?

不一定

函數同樣要注意這點:如果所申請的內存塊大於目前堆上剩余內存塊(整塊),則內存分配會失敗,函數返回NULL。注意這里說的“堆上剩余內存塊”不是所有剩余內存塊之和,因為malloc函數申請的是連續的一塊內存。既然malloc函數申請內存有不成功的可能,那我們在使用指向這塊內存的指針時,必須用if(NULL!=p)語句來驗證內存確實分配成功了。

用 malloc 函數申請 0 字節內存

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

內存釋放


既然有分配,那就必須有釋放。不然的話,有限的內存總會用光,而沒有釋放的內存卻在空閑。與malloc對應的就是free函數了。free函數只有一個參數,就是所要釋放的內存塊的首地址。比如上例:

free(p);

free函數看上去挺狠的,但它到底作了什么呢?

其實它就做了一件事:斬斷指針變量與這塊內存的關系。

比如上面的例子,我們可以說malloc函數分配的內存塊是屬於p的,因為我們對這塊內存的訪問都需要通過p來進行。free函數就是把這塊內存和p之間的所有關系斬斷。從此p和那塊內存之間再無瓜葛。至於指針變量p本身保存的地址並沒有改變,但是它對這個地址處的那塊內存卻已經沒有所有權了。那塊被釋放的內存里面保存的值也沒有改變,只是再也沒有辦法使用了

這就是free函數的功能。按照上面的分析,如果對p連續兩次以上使用free函數,肯定會發生錯誤。因為第一使用free函數時,p所屬的內存已經被釋放,第二次使用時已經無內存可釋放了。關於這點,我(陳正沖老師)上課時讓學生記住的是:一定要一夫一妻制,不然肯定出錯。

malloc兩次只free一次會內存泄漏;malloc一次free兩次肯定會出錯。也就是說,在程序中malloc的使用次數一定要和free相等,否則必有錯誤。這種錯誤主要發生在循環使用malloc函數時,往往把malloc和free次數弄錯了。

4.內存釋放之后

既然使用free函數之后指針變量p本身保存的地址並沒有改變,那我們就需要重新把p的值變為NULL:

1
p = NULL;
這個NULL就是我們前面所說的“栓野狗的鏈子”。如果你不栓起來遲早會出問題的。比如:

在free(p)之后,你用if(NULL!=p)這樣的校驗語句還能起作用嗎?
例如:

char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); /* p 所指的內存被釋放,但是p所指的地址仍然不變*/
⋯
if (NULL != p)
{
/* 沒有起到防錯作用*/
strcpy(p, “world”); /* 出錯*/
}

釋放完塊內存之后,沒有把指針置NULL,這個指針就成為了“野指針”,也有書叫“懸垂指針”。這是很危險的,而且也是經常出錯的地方。所以一定要記住一條:free完之后,一定要給指針置NULL。

內存已經被釋放了,但是繼續通過指針來使用


這里一般有三種情況:

第一種:就是上面所說的,free(p)之后,繼續通過p指針來訪問內存。解決的辦法就是給p置NULL。

第二種:函數返回棧內存。這是初學者最容易犯的錯誤。比如在函數內部定義了一個數組,卻用return語句返回指向該數組的指針。解決的辦法就是弄明白棧上變量的生命周期。

第三種:內存使用太復雜,弄不清到底哪塊內存被釋放,哪塊沒有被釋放。解決的辦法是重新設計程序,改善對象之間的調用關系。

參考:陳正沖老師的《c語言深度剖析》。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM