C語言學習之動態記憶體分配第一講

2021-07-09 10:11:24 字數 3543 閱讀 9761

這裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放

一、動態記憶體分配

陣列的元素儲存於記憶體的連續位置,陣列可以在宣告後編譯就分配所需記憶體,也可以使用動態記憶體分配在執行時為他分配記憶體。

1.1當宣告陣列時,必須用乙個編譯時常量為陣列指定陣列長度,這種分配記憶體的方的優缺點如下:

1.1.1優點:

1. 使用簡單只需在編譯時常量指定陣列長度。

1.1.2缺點:

1.如果不確定陣列內執行時具體需要多少記憶體,一旦實際元素超過分配的記憶體則出錯。

2.如果為了解決第乙個缺點而大量宣告記憶體空間,一旦實際元素過少時會嚴重浪費記憶體空間

1.2執行記憶體分配和釋放函式

這些函式都在c函式庫stdlib.h中

1.2.1 malloc  

1.函式原型:void  *malloc(size_t  size);

size_t是乙個無符號型別定義於stdlib.h中 size即為分配的記憶體大小返回值是指向記憶體起始位置的指標,由於使用返回指標的型別為void  * 型指標所以標準的表示void  *型別指標可以轉換成任意型別指標,但是有些編譯器可能要求使用強制型別轉換。

char* p; 

p=(char*)malloc(20);

記憶體並未初始化,如果需要的話則需要手動初始化或者使用calloc函式。實際分配記憶體時可能迴避你要求的超微多一旦,這個由編譯器決定所以不能指望他肯定會分配連續的要求記憶體。如果申請記憶體為空的或者申請的記憶體系統無法滿足要求,則會返回乙個null指標,所以每個申請的記憶體必須檢查返回指標,確保它並非null。null 實際上是字面值常量0。他在這裡騎著視覺提醒作用告訴我們我們測試的是乙個指標而不是整數。

1.2.2calloc

1.函式原型: void  *calloc( size_t  num_elements,  size_t  exement_size);

calloc不同於malloc是calloc會在返回指標之前把申請記憶體初始化為0,如果0不是想初始化的內容則這裡會浪費時間。num_element是要初始化的元素數量而 element_size時要初始化元素每個占用位元組數,通過這些可以計算總共需要的分配的記憶體。

1.2.3 realloc

1.函式原型:void  *realloc( void  *ptr , size_t  new_size);

realloc用於修改乙個原來已經分配的記憶體塊的大小。可以擴大乙個記憶體塊則原來的內容保留新增加的記憶體新增到原先記憶體塊後面,可以縮小記憶體則縮小尾部的部分記憶體,剩餘的記憶體和資料保留。如果原先的記憶體無法改變大小,則realloc會重新分配乙個正確的大小的記憶體,並把原先的內容複製到新的快上,新詞在使用realloc後你就不能在使用原來的指向記憶體的指標了,而是應該使用realloc所返回的新指標。

2 特殊情況:

(1)如果ptr = null 那麼相當於呼叫malloc (size) size=0那麼相當於呼叫了free(prt)。

(2)如果修改的記憶體小於實際的記憶體則會直接返回原來的記憶體位址。

(3)如果修改的記憶體大於實際的記憶體

1.realloc是從堆上分配記憶體的,當擴大一塊記憶體空間時, realloc()試圖直接從堆上現存的資料後面的那些位元組中獲得附加的位元組,如果能夠滿足,則可以成功則返回原來記憶體指標位址。

2.若堆的記憶體不足時則直接在堆裡找一塊新的記憶體為new_size的空間同時把原先的內容拷貝到新位址函式返回新記憶體位址, 這

裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放

這裡原始記憶體中的資料還是保持不變的。當記憶體不再使用時,應使用free()函式將記憶體塊釋放。這

裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放 3.

這 裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放

如果申請失敗,將返回null,此時,原來的指標仍然有效

下面就舉兩個例子,來說明一下。

1) realloc() 第一種行為引發的bug

void

*ptr =

realloc

(ptr, new_size);

if(!ptr)

這裡就引出了乙個記憶體洩露的問題,當realloc() 分配失敗的時候,會返回null。但是引數中的 ptr 的記憶體是沒有被釋放的。如果直接將realloc()的返回值賦給ptr。那麼當申請記憶體失敗時,就會造成ptr原來指向的記憶體丟失,造成記憶體游離和洩露。

正確的處理應該是這樣:

void

*new_ptr =

realloc

(ptr, new_size);

if(!new_ptr)

ptr = new_ptr

2) 第三種行為引發的bug

實際上,malloc(0)是合法的語句,會返還乙個合法的指標,且該指標可以通過free去釋放。這就造成了很多人對realloc()的錯誤理解,認為當size為0時,實際上realloc()也會返回乙個合法的指標,後面依然需要使用free去釋放該記憶體。

void

*new_ptr =

realloc

(old_ptr, new_size);

//其它**

free

(new_ptr);

由於錯誤的認識,不去檢驗new_size是否為0,還是按照new_size不為0的邏輯處理,最後並free(new_ptr)。這裡就引入了double free的問題,造成程式崩潰。

所以,realloc() 這個設計並不怎麼優良的函式陷阱還是不少的,一不小心就踩雷了,上面只是兩個簡單的小例子,大家在實際使用的時候還應該注意一些其他小問題。

1.2.4 free 

1.函式原型:void  free(void *pointer);這

裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放

功 能: 與malloc()函式配對使用,釋放malloc函式申請的動態記憶體。(另:對於free(p)這句語句,如果p 是null 

指標,那麼free 對p 無論操作多少次都不會出問題。如果p 不是null 指標,那麼free 對p連續操作兩次就會導致程式執行錯誤。

錯誤的范文分配記憶體之外的區域所引起的後果類似越界訪問陣列,但這個錯誤還可能破壞可用記憶體池,導致程式失敗,如果乙個指標不是早先的malloc,calloc,realloc函式反悔的,他是不能作為引數傳給free函式的。你也不能只是放一塊記憶體的一部分。如果傳給free函式乙個指標沒讓他釋放非動態分配的記憶體可能導致程式立即終止或者晚些時候終止。

記憶體洩露是指記憶體被動態分配以後,當他不在被使用時未被釋放。記憶體洩露會增加程式的體積有可能導致程式或者系統崩潰。

這裡原始記憶體中的資料還是保持不變的。

當記憶體不再使用時,

應使用free()

函式將記憶體塊釋放

C語言學習筆記 動態記憶體分配

記憶體分割槽 說明 程式 區 code area 存放函式體的二進位制 靜態資料區 data area 也稱全域性資料區,包含的資料型別比較多,如全域性變數 靜態變數 一般常量 字串常量。其中 注意 靜態資料區的內存在程式結束後由作業系統釋放。堆區 heap area 一般由程式設計師分配和釋放,若...

C語言學習筆記 動態記憶體分配

1 c 語言中的一切操作都是基於記憶體的。2 變數和陣列都是記憶體的別名。記憶體分配由編譯器在編譯期間決定 定義陣列的時候必須指定陣列長度 陣列長度是在編譯期就必須確定的 3 但是程式執行的過程中,可能需要使用一些額外的記憶體空間 1 malloc 和 free 用於執行動態記憶體分配的釋放 2 m...

C語言學習之動態記憶體管理

1 問什麼要動態記憶體管理?在進行資料儲存的時候,我們經常的做法是利用陣列開闢指定大小的空間用以儲存資料,但是陣列的具體大小取決於輸入的資料,因此往往在程式執行時才知道所需陣列的記憶體空間的大小。為了達到對記憶體空間的合理使用,這就要就我們根據輸入資料的不同來開闢不同大小的記憶體空間,繼而出現動態記...