1. malloc()函式
1.1 malloc的全稱是memory allocation,中文叫動態記憶體分配。
原型:extern void *www.cppcns.commalloc(unsigned int num_bytes);
說明:分配長度為num_bytes位元組的記憶體塊。如果分配成功則返回指向被分配記憶體的指標,分配失敗返回空指標null。當記憶體不再使用時,應使用free()函式將記憶體塊釋放。
1.2 void *malloc(int size);
說明:malloc 向系統申請分配指定size個位元組的記憶體空間,返回型別是 void* 型別。void* 表示未確定型別的指標。c,c++規定,void* 型別可以強制轉換為任何其它型別的指標。
備註:void* 表示未確定型別的指標,更明確的說是指申請記憶體空間程式設計客棧時還不知道使用者是用這段空間來儲存什麼型別的資料(比如是char還是int或者...)
1.3 free
void free(void *firstbyte): 該函式是將之前用malloc分配的空間還給程式或者是作業系統,也就是釋放了這塊記憶體,讓它重新得到自由。
1.4注意事項
1)申請了記憶體空間後,必須檢查是否分配成功。
2)當不需要再使用申請的記憶體時,記得釋放;釋放後應該把指向這塊記憶體的指標指向null,防止程式後面不小心使用了它。
3)這兩個函式應該是配對。如果申請後不釋放就是記憶體洩露;如果無故釋放那就是什麼也沒有做。釋放只能一次,如果釋放兩次及兩次以上會出現錯誤(釋放空指標例外,釋放空指標其實也等於啥也沒做,所以釋放空指標釋放多少次都沒有問題)。
4)雖然malloc()函式的型別是(void *),任何型別的指標都可以轉換成(void *),但是最好還是在前面進行強制型別轉換,因為這樣可以躲過一些編譯器的檢查。
1.5 malloc()到底從**得到了記憶體空間?
答案是從堆裡面獲得空間。也就是說函式返回的指標是指向堆裡面的一塊記憶體。作業系統中有乙個記錄空閒記憶體位址的鍊錶。當作業系統收到程式的申請時,就會遍歷該鍊錶,然後就尋找第乙個空間大於所申請空間的堆結點,然後就將該結點從空閒結點鍊錶中刪除,並將該結點的空間分配給程式。
2. new運算子
2.1 c++中,用new和delete動態建立和釋放陣列或單個物件。
動態建立物件時,只需指定其資料型別,而不必為該物件命名,new表達程式設計客棧式返回指向該新建立物件的指標,我們可以通過指標來訪問此物件。
int *pi=new int;
這個new表示式在堆區中分配建立了乙個整型物件,並返回此物件的位址,並用該位址初始化指標pi 。
2.2 動態建立物件的初始化
動態建立的物件可以用初始化變數的方式初始化。
int *pi=new int(100); //指標pi所指向的物件初始化為100
string *ps=new string(10,'9');//*ps 為「9999999999」
如果不提供顯示初始化,對於類型別,用該類的預設建構函式初始化;而內建型別的物件則無初始化。
也可以對動態建立的物件做值初始化:
int *pi=new int( );//初始化為0
int *pi=new int;//pi 指向乙個沒有初始化的int
string *ps=new string( );//初始化為空字串 (對於提供了預設建構函式的類型別,沒有必要對其物件進行值初始化)
2.3 撤銷動態建立的物件
delete表示式釋放指標指向的位址空間。
delete pi ;// 釋放單個物件
delete [ ]pi;//釋放陣列
如果指標指向的不是new分配的記憶體位址,則使用delete是不合法的。
2.4 在delete之後,重設指標的值
delete p; //執行完該語句後,p變成了不確定的指標,在很多機器上,儘管p值沒有明確定義,但仍然存放了它之前所指物件的位址,然後p所指向的記憶體已經被釋放了,所以p不再有效。此時,該指標變成了懸垂指標(懸垂指標指向曾經存放物件的記憶體,但該物件已經不存在了)。懸垂指標往往導致程式錯誤,而且很難檢測出來。
一旦刪除了指標所指的物件,立即將指標置為0,這樣就非常清楚的指明指標不再指向任何物件。(零值指標:int *ip=0;)
2.5 區分零值指標和null指標
零值指標,是值是0的指標,可以是任何一種指標型別,可以是通用變體型別void*也可以是char*,int*等等。
空指標,其實空指標只是一種程式設計概念,就如乙個容器可能有空和非空兩種基本狀態,而在非空時可能裡面儲存了乙個數值是0,因此空指標是人為認為的指標不提供任何位址訊息。
2.6 new分配失敗時,返回什麼?
2023年前,c++一直要求在記憶體分配失敗時operator new要返回0,現在則是要求operator new丟擲std::bad_alloc異常。很多c++程式是在編譯器開始支援新規範前寫的。c++標準委員會不想放棄那些已有的遵循返回0規範的**,所以他們提供了另外形式的operator new(以及operator new)以繼續提供返回0功能。這些形式被稱為「無丟擲」,因為他們沒用過乙個throw,而是在使用new的入口點採用了nothrow物件:
class widget ;
widget *pw1 = new widget;// 分配失敗丟擲std::bad_alloc
if (pw1 == 0) ... // 這個檢查一定失敗
widget *pw2 = new (nothrow) widget; // 若分配失敗返回0
if (pw2 == 0) ... // 這個檢查可能會成功
3. malloc和new的區別
3.1 new 返回指定型別的指標,並且可以自動計算所需要大小。
比如:
1)int *p;
p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);
或: 程式設計客棧
int* parr;
parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 程式設計客棧100;
2)而 malloc 則必須要由我們計算位元組數,並且在返回後強行轉換為實際型別的指標。
int* p;
p = (int *) malloc (sizeof(int)*128);//分配128個(可根據實際需要替換該數值)整型儲存單元,並將這128個連續的整型儲存單元的首位址儲存到指標變數p中
double *pd=(double *) malloc (sizeof(double)*12);//分配12個double型儲存單元,並將首位址儲存到指標變數pd中
3.2 malloc 只管分配記憶體,並不能對所得的記憶體進行初始化,所以得到的一片新記憶體中,其值將是隨機的。
除了分配及最後釋放的方法不一樣以外,通過malloc或new得到指標,在其它操作上保持一致。
4.有了malloc/free為什麼還要new/delete?
1)malloc與free是c++/c語言的標準庫函式,new/delete是c++的運算子。它們都可用於申請動態記憶體和釋放記憶體。
2)對於非內部資料型別的物件而言,光用maloc/free無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行析構函式。由於malloc/free是庫函式而不是運算子,不在編譯器控制許可權之內,不能夠把執行建構函式和析構函式的任務強加於malloc/free。
因此c++語言需要乙個能完成動態記憶體分配和初始化工作的運算子new,以及乙個能完成清理與釋放記憶體工作的運算子delete。注意new/delete不是庫函式。
我們不要企圖用malloc/free來完成動態物件的記憶體管理,應該用new/delete。由於內部資料型別的「物件」沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。
3)既然new/delete的功能完全覆蓋了malloc/free,為什麼c++不把malloc/free淘汰出局呢?這是因為c++程式經常要呼叫c函式,而c程式只能用malloc/free管理動態記憶體。
如果用free釋放「new建立的動態物件」,那麼該物件因無法執行析構函式而可能導致程式出錯。如果用delete釋放「malloc申請的動態記憶體」,結果也會導致程式出錯,但是該程式的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。
本文標題: c/c++動態分配與釋放記憶體的區別詳細解析
本文位址:
記憶體動態分配與釋放
1 c語言的函式malloc和free 1 函式malloc和free在標頭檔案中的原型及引數 void malloc size t size 動態配置記憶體,大小有size決定,返回值成功時為任意型別指標,失敗時為null。void free void ptr 釋放動態申請的記憶體空間,呼叫fre...
記憶體動態分配與釋放
1 c語言的函式malloc和free 1 函式malloc和free在標頭檔案中的原型及引數 void malloc size t size 動態配置記憶體,大小有size決定,返回值成功時為任意型別指標,失敗時為null。void free void ptr 釋放動態申請的記憶體空間,呼叫fre...
記憶體動態分配與釋放
記憶體的動態分配需要使用函式malloc,函式free和運算子sizeof來實現。函式malloc的原型是 void malloc unsigned int size 函式malloc的作用是在記憶體中分配乙個長度為size的連續儲存空間。函式的返回值是乙個指向分配空間的起始位置的指標。如果分配空間...