C 基礎 動態記憶體分配

2021-06-28 17:12:08 字數 2873 閱讀 9971

1.c中的動態記憶體分配

在程式執行的過程中,我們需要能夠自由地建立和銷毀物件。

在c中,提供了動態記憶體分配(dynemic memory alloction)函式malloc()和free(),這些函式可以在執行時從堆中分配單元。

然而,在c++中這些函式將無法按照預期的情況去執行。因為建構函式不允許我們向它傳遞記憶體位址來進行初始化。而將物件的定義和初始化分離是一件十分危險的事情,可能會出現以下情況 :

①分配記憶體之後忘記初始化;

②在物件的初始化完成之前就對它進行操作;

③把錯誤規模的物件傳遞給它。

不正確的初始化要對大部分程式設計問題承擔責任,因為在堆上建立物件時,確保建構函式的呼叫是非常重要的。

c++使動態語言分配成為核心,malloc()和free()是庫函式,因此不在編譯器的控制範圍內。我們需要乙個完成動態記憶體分配及初始化組合動作的運算子和乙個完成清理及釋放組合動作的運算子,編譯器仍可以保證所有的建構函式和析構函式都會被使用。

物件的建立與釋放

當建立乙個物件時,會發生兩件事:

①為物件分配記憶體;

②呼叫物件的建構函式來初始化物件;

c++強調物件在**和如何被呼叫都無關緊要,但建構函式必須要被呼叫。

在分配記憶體時,我們有很多方式:

①在靜態儲存區域,儲存空間在程式開始之前就可以分配,這個儲存空間在程式的整個執行期間都存在。(全域性變數&static)

②無論何時到達乙個特殊的執行點「」時,堆疊指標上移,這個記憶體單元出棧並被釋放,但在執行前,必須明確地知道需要多少個儲存單元。(區域性變數)

③儲存單元也可以從一塊被稱為堆的空間中分配。這被稱為動態記憶體分配。在執行時呼叫程式分配這些記憶體。這意味著可以在任何時候確定分配記憶體的大小。當然也需要負責決定何時釋放記憶體,這塊記憶體的生存期由我們決定,而不受程式的範圍決定。

1.c從堆中獲取儲存單元的方法

c在它的標準庫函式中提供了

從堆中申請記憶體的malloc()、calloc()、realloc()

釋放記憶體返回給堆的函式free()

class obj 

void destory()

};int main(void)

使用malloc()時,使用者必須指明物件的長度。由於malloc()只分配一塊記憶體而不是生成乙個物件,因此返回乙個(void *)型別指標,c++不允許將乙個void *型別的指標賦給其它型別的指標,所以必須做型別的轉換。

malloc()可能找不到可分配的記憶體,所以必須檢查返回的指標。

物件在使用之前必須初始化,沒有使用建構函式的士隱建構函式不能被顯式地呼叫——它是在物件被建立時由編譯器呼叫。使用malloc()時會將定義和初始化分開,會產生危險的後果。

2.c++的改進方案

c++中的解決方案是把建立物件所需的所有動作都封裝在乙個稱為new的運算子

把釋放物件所需的所有動作都封裝在乙個稱為delete的運算子

簡單來說:new = malloc() + constructor() ;

delete = distructor() + free() ;

如果寫出下面的語句

obj * ptrobj = new obj(1 , 2) ;

執行時等價於呼叫malloc(sizeof(obj)),並使(1 , 2)作為引數來呼叫建構函式,this指標指向返回值的位址。並且new還會自動進行檢查記憶體是否分配成功。

new使得在堆中動態分配分配建立物件變得簡單。

delete表示式首先呼叫析構函式,然後釋放記憶體,引數是乙個物件的位址。用法如下:

delete ptrobj ;

如果想對乙個void *型別的指標進行delete操作,這可能成為程式的錯誤,除非這個void *指標指向簡單的內容,否則將不會執行析構函式。如果我們在一段看起來正常的程式中發現了記憶體丟失的情況,那麼就搜尋所有的語句

1.new的物件是否都被delete釋放

2.delete釋放的指標是否是void * 型別

3.陣列的new和delete

建立乙個物件陣列同樣簡單,應為陣列中的每乙個物件呼叫建構函式。

在物件陣列中,每個物件會自動呼叫預設建構函式。

obj * ptrobj = new obj[100];

表示在堆上分配100個ob物件,並為每個物件都呼叫建構函式。

但我們得到的ptrobj是指向這個物件陣列的起始位址,可以用ptrobj[3]的形式來選擇元素,但如果我們使用

delete ptrobj ;
表示給位址指向的obj物件呼叫析構函式,然後釋放記憶體。對於ptrobj,後面的99個物件都沒有呼叫析構。

解決方法是給編譯器乙個提示,告訴它delete釋放的是乙個起始位址

delete ptrobj ;

[ ]是乙個標識,不需要填具體數字,因為我們需要釋放的是整個陣列,需要填數字的話反而會引起麻煩。

4.過載new和delete

當系統提供的預設new和delete不適合解決實際遇到的問題時,我們可以選擇過載new和delete運算子。

#include #include #include using namespace std ;

class complex

~complex()

};void * friend operator new(size_t sz)

void * friend operator delete(size_t sz)

這就是過載new和delete的通常形式。

有一點尤為重要,過載運算子new和delete時,只需要實現分配記憶體的部分即可,其他功能由編譯器負責呼叫,不需要我們去控制。

C 基礎 動態記憶體分配

動態申請記憶體操作符 new 釋放記憶體操作符delete 例 動態建立物件舉例 include using namespace std class point class arrayofpoints arrayofpoints point element int index private poi...

c語言動態記憶體分配 C 動態記憶體分配

動態記憶體分配 雖然通過陣列就可以對大量的資料和物件進行有效地管理,但是很多情況下,在程式執行之前,我們並不能確切地知道陣列中會有多少個元素。這種情況下,如果陣列宣告過大,就會造成浪費 宣告過小,就會影響處理。在c 中,動態記憶體分配技術可以保證程式在執行過程中按照需要申請適量記憶體,使用後釋放,從...

C語言基礎 動態記憶體分配

void malloc size t size malloc的引數是需要分配的 位元組 數 請求成功返回乙個指向被分配記憶體塊起始位置的指標 否則返回 null 指標 所以對每個從該函式返回的指標都需進行檢查 例項 分配乙個100個int16u型陣列 int16u lp tmp lp tmp mal...