C語言--動態內存分配

1)什麼是動態內存分配、靜態內存分配。

百度百科中這樣定義

靜態內存分配:分配內存大小的是固定,比如定義一個數組,數組的大小是我們提前定義好的,一直到程序結束。

動態內存分配:動態內存分配(Dynamic Memory Allocation)就是指在程序執行的過程中動態地分配或者回收存儲空間的分配內存的方法。

2)爲什麼要進行動態內存分配?

(1)傳統數組(即靜態內存分配)有着如下缺點:

int a[5];//正確
int len = 5; int a[len];//錯誤
  • 數組的長度必須事先確定,而且只能是常整數,不能是變量

  • 傳統形式定義的數組,該數組的內存程序員無法手動釋放,在一個函數運行期間,系統爲該函數中數組所分配的空間會一直存在,直到該函數運行完畢時,數組的空間纔會被系統釋放。

  • 數組的長度一旦定義,其長度就不能更改,數組的長度不能在函數運行的過程中動態的擴充或縮小。
  • A函數定義的數組,在A函數運行期間可以被其它函數使用,但A函數運行完畢之後,A函數中的數組將無法被其他函數使用。也就是說,傳統方式定義的數組不能跨函數使用。

​ 而動態內存分配就很好解決了傳統數組的這4個缺陷。

(2)其他情況:

​ 如果我們操作的數據對象太大,我們使用的數據大部分時候都默認保存在棧(stack)裏面,由系統去管理,會自動給分配內存,但是stack很小,就那麼幾M,如果你讀取一個幾十M的文本內容然後保存到一個字符串裏,stack肯定會被撐爆了。

​ 另外如果你想準確的控制內存的釋放.比如內存比較緊缺,你用完一塊內存後就想立馬釋放掉.如果系統自動去釋放的話可能得等到變量生命週期結束時再釋放.不會做得到立馬釋放.

​ 基於上面等一些原因於是出現了堆(heap),這是由用戶自己控制的一片內存區,比stack大多了.你可以自由的在裏面申請空間釋放空間

3)C語言的內存模型–堆、棧、靜態區

靜態區:保存自動全局變量和static 變量(包括static 全局和局部變量)。靜態區的內容在總個程序的生命週期內都存在,由編譯器在編譯的時候分配。

棧:保存局部變量。棧上的內容只在函數的範圍內存在,當函數運行結束,這些內容也會自動被銷燬。其特點是效率高,但空間大小有限。

堆:由malloc 系列函數或new 操作符分配的內存。其生命週期由free 或delete 決定。在沒有釋放之前一直存在,直到程序結束。其特點是使用靈活,空間比較大,但容易出錯。

4)如何使用malloc 函數分配內存(動態內存分配)

(1)動態構造一個int型一維數組

(void *)malloc(int size)

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

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

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

(2)內存釋放

既然有分配,那就必須有釋放。不然的話,有限的內存總會用光,而沒有釋放的內存卻在空閒。與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 次數弄錯了。

(3)內存釋放之後

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

p = NULL;

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

5)內存泄漏

內存泄漏(Memory Leak)是指程序中己動態分配的堆內存由於某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重後果。

所謂內存泄露是因爲堆的空間北我們動態分配用完了,這樣當我們再去使用動態分配堆的空間的時候就沒有足夠的空間讓我們使用了,這樣就需要佔有原來的空間,也就是會把其他的空間來儲存我們鍵入的值,這樣會導致原來儲存的數據被破壞掉,導致了內存的泄露了。

6)總結:什麼時候需要進行動態內存分配?

(1)無法預先確定所需要的內存空間大小

(2)要分配的空間太大超過站的大小,一般來說超過2M大小時

(3)內存中的數據需要帶回使用,不能放在棧區,智能用動態內存分配

(4)內存較小,想充分利用內存

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章