動態記憶體管理

2021-08-21 08:12:43 字數 4406 閱讀 3240

資料的元素儲存於記憶體中連續的位置上,當乙個陣列被宣告時,他所需要的內存在編譯時就被分配。當然,我們也可以使用動態記憶體分配在執行時為他分配記憶體。在動態記憶體分配中我們需要經常用到malloc,free,calloc,realloc這四個函式

malloc/calloc/realloc的作用

void* realloc(void* ptr, unsigned newsize);

void* malloc(unsigned size);

void* calloc(size_t nelem, size_t elsize);

1.malloc和free分別用於執行動態記憶體分配和釋放。當我們需要呼叫一塊記憶體時,就可以選擇malloc函式,malloc會從記憶體中呼叫一塊未被初始化的合適的記憶體,並向程式返回乙個指向該塊記憶體的指標。當一塊以前分配的記憶體不再使用時,我們要用free函式把記憶體塊歸還給記憶體池。

這兩個函式的原型如下所示,他們都在標頭檔案stdlib.h中實現:

void *malloc( size_t size );

void free( void *pointer );

2.realloc用來給乙個已經分配了記憶體空間的指標重新分配一段長度為newsize的空間,返回的首位址有以下幾種情況:

(1).當原指標所在空間不足已分配newsize大小的空間的時候, 此時系統就會找一段新的空間來給其分配一段新的記憶體空間,此時的指標返回值就和原來的指標的值不一樣

(2).當原來指標所在位置剩餘空間還足以分配newsize大小的空間的時候,此時就在原來的空間上分配一段長度為newsize大小的空間. 返回值和原來的指標的值相同

(3).記憶體申請失敗, 返回0

注意: realloc在動態分配記憶體的時候會將其原來的空間所儲存的內容進行拷貝到新的空間

3.calloc是申請nelem個大小為elsize的空間,同時會將其每乙個新開闢的空間進行初始化為0

malloc/calloc/realloc的區別

malloc與calloc,realloc都可以用來動態分配記憶體空間,但兩者也存在著一些區別:

1.malloc函式有乙個引數,即要分配的記憶體空間的大小

2.calloc有兩個引數,分別為元素的數目和每個元素的大小,這兩個引數的乘積就是要分配的記憶體空間的大小

3.如果分配記憶體空間成功,則兩者都返回分配的記憶體空間的首位址函式的程式開始

4.malloc不能初始化所分配的記憶體空間,而calloc能

5.由於malloc分配的記憶體空間原來沒有被使用過,則其中每一位可能都是零,反之,如果這部分記憶體曾經被使用過,在其中可能留有各種各樣的資料,也就是說,使用malloc時(記憶體空間還沒有被重新分配)能正常執行,但經過一段時間(記憶體空間已經重新分配)可能會出現問題

6.函式calloc將分配的記憶體空間中的每一位初始化為0,也就是說如果你為字元型或資料型別的元素分配記憶體空間,那麼這些元素將被初始化為0,如果你是為指標型別 的元素分配記憶體空間,那麼這些元素會被初始化為空指標,如果你為實型資料分配記憶體,這些元素會被初始化為浮點型的0。

7.realloc是給乙個已經分配了記憶體的位址指標重新分配空間,引數包括原因的空間位址和重新申請的位址長度

注意

堆上的記憶體需要使用者自己來管理,動態malloc/calloc/realloc的空間,必須free掉,否則會造成記憶體洩露;棧上空間具有函式作用域,在函式結束後系統自動**,不用使用者管理。棧上,使用_alloc在棧上動態開闢記憶體,棧上開闢的記憶體由編譯器自動維護,不需要使用者顯式釋放。

常見的動態記憶體錯誤

(1)小心越界訪問

(2)malloc和free成對使用

(3)對null指標進行解引用操作

(4)對已經釋放的動態記憶體的使用

(5)對動態開闢的記憶體的多次釋放

(6)對動態開闢的記憶體的一部分進行釋放

(7)free釋放一塊非動態開闢的記憶體

程序虛擬位址空間

堆和棧的區別:

1)空間大小:棧的記憶體空間是連續的,空間大小通常是系統預先規定好的,即棧頂位址和最大空間是確定的;而堆得記憶體空間是不連續的,由乙個記錄空間空間的鍊錶負責管理,因此記憶體空間幾乎沒有限制,在32位系統下,記憶體空間大小可達到4g

2)管理方式:棧由編譯器自動分配和釋放,而堆需要程式設計師來手動分配和釋放,若忘記delete,容易產生記憶體洩漏。

3)生長方向不同:對於棧,他是向著記憶體位址減小的方向生長的,這也是為什麼棧的記憶體空間是有限的;而堆是向著記憶體位址增大的方向生長的

4)碎片問題:由於棧的記憶體空間是連續的,先進後出的方式保證不會產生零碎的空間;而堆分配方式是每次在空閒鍊錶中遍歷到第乙個大於申請空間的節點,每次分配的空間大小一般不會正好等於申請的記憶體大小,頻繁的new操作勢必會產生大量的空間碎片

5)分配效率:棧屬於機器系統提供的資料結構,計算機會在底層對棧提供支援,出棧進棧由專門的指令執行,因此效率較高。而堆是c/c++函式庫提供的,當申請空間時需要按照一定的演算法搜尋足夠大小的記憶體空間,當沒有足夠的空間時,還需要額外的處理,因此效率較低。

野指標出現的幾種情況

(1)指標變數沒有被初始化。任何指標變數剛被建立時不會自動成為null指標,它的預設值是隨機的,它會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼將指標設定為null,要麼讓它指向合法的記憶體。

(2)指標p被free或者delete之後,沒有置為null,讓人誤以為p是個合法的指標.

(3)指標操作超越了變數的作用範圍

malloc/free new/delete之間的區別與聯絡

相同點:

(1)都是申請記憶體,釋放記憶體,free和delete可以釋放null指標;

(2)都必須配對使用,這裡的配對使用,可不能理解為乙個new/malloc就對應乙個delete/free,而是指在作用域內,new/malloc所申請的記憶體,必須被有效釋放,否則將會導致記憶體洩露。

new/delete的功能完全覆蓋了malloc/free,為什麼c++還保留malloc/free呢?因為c++程式經常要呼叫c函式,而c程式只能用malloc/free管理動態記憶體。如果用free釋放「new建立的動態物件」,那麼該物件因無法執行析構函式而可能導致程式出錯。如果用delete釋放「malloc申請的動態記憶體」,理論上講程式不會出錯,但是該程式的可讀性很差。所以new/delete、malloc/free必須配對使用。

不同點:

操作物件有所不同。

malloc與free是c++/c 語言的標準庫函式,new/delete 是c++的運算子。對於非內部資料類的物件而言,光用maloc/free 無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式, 物件消亡之前要自動執行析構函式。由於malloc/free 是庫函式而不是運算子,不在編譯器控制許可權之內,不能夠把執行建構函式和析構函式的任務強加malloc/free。

用法上也有所不同。

1、new自動計算需要分配的空間,而malloc需要手工計算位元組數

2、new是型別安全的,而malloc不是,比如:

int* p = new

float[2]; // 編譯時指出錯誤

int* p = malloc(2*sizeof(float)); // 編譯時無法指出錯誤

new operator 由兩步構成,分別是 operator new 和 construct

3、operator new對應於malloc,但operator new可以過載,可以自定義記憶體分配策略,甚至不做記憶體分配,甚至分配到非記憶體裝置上。而malloc無能為力。

4、new將呼叫constructor,而malloc不能;delete將呼叫destructor,而free不能。

5、malloc/free要庫檔案支援,new/delete則不要。

舉個例子

delete objects; // 正確的用法

delete objects; // 錯誤的用法

後者相當於delete objects[0],漏掉了另外99 個物件。(objects是陣列首位址)

new[n]和delete

new[n]呼叫operator new分配空間, 呼叫建構函式對每乙個物件進行初始化

delete[n]呼叫n次析構函式清理物件,同時呼叫operator delete釋放空間

delete怎麼知道n是多少

原因在這裡, 在呼叫new[n]的時候, operator new 會額外開闢四個位元組的空間來存放n的大小,然後返回4個位元組後的起始位置, 所以當呼叫delete的時候, 它會先向前挪動四個位元組, 此時就可以看到n的大小, 然後然後呼叫析構函式, 再將對應的物件的空間進行釋放, 最後呼叫operatordelete() 以及 free釋放最前面的四個位元組所占有的空間

動態記憶體管理

首先應該明白物件的三種內部的儲存方式 自動儲存,靜態儲存,和動態儲存。當執行離開當期程式塊的時候,堆疊指標返回到它進入程式塊 之前的地方,有效的銷毀了那個程式塊的自動變數。重新進入這個塊會再次建立所有的自動變數。靜態物件宣告或者在檔案域中。動態物件是存在系統呼叫 的在執行期中建立並且儲存在堆中,這是...

動態 記憶體管理

定義變數時,必須制定其資料型別和名字。而動態建立物件時,只需指定其資料型別,而不必為該物件命名。取而代之的是,new表示式返回指向新建立物件的指標,我們通過該指標來訪問此物件。int i int pi new int 這個new表示式在自由儲存區中分配建立了乙個整型物件,並返回此物件的位址,並用該位...

動態記憶體管理

c語言使用malloc calloc realloc free進行動態記憶體管理。void test c 通過new和delete動態管理記憶體。new delete動態管理物件。new delete動態管理物件陣列。void test void test int globalvar 1 stati...