malloc/calloc/realloc/free與new/delete對比
C動態申請記憶體函式:
【堆上】
函式原型:void *malloc(size_t size);
函式功能:申請size個位元組的記憶體空間,返回該段空間的首地址,該空間裡面的東西是隨機值。
返回值:始終是void*,申請成功,返回空間的首地址,否則返回NULL,所以使用這個函式一定要對返回值進行判斷。
例:int *p = malloc(10 * 4);
首先沒有對返回值進行強制轉換,編譯時會報警告;其次,引數給了個4,只是代表32為機器下一個整型的長度,可移植性不好;最後,沒有進行引數檢測,萬一分配失敗,則下面對這個指標的操作1可能會導致崩潰。建議像下面這樣使用:
int *p = (int *)malloc(n * sizeof(int)); if (NULL == p) { //do something or exit }
函式原型:void *calloc(size_t num, size_t size);
函式功能:申請num個元素陣列的記憶體塊,申請的記憶體空間會用0來初始化。
num:元素的個數
size:元素型別大小
返回值:申請成功,返回該段記憶體的首地址,申請失敗返回NULL,使用時一定要注意監測是否分配成功。
函式原型:void *realloc(void *ptr, size_t size);
引數說明:ptr:需要改變的指標 size:要改變的記憶體byte數,可比原記憶體空間大或者小
函式功能:先判斷當前的指標指向記憶體塊後面是否有足夠的連續空間,如果有擴大,直接返回源地址,如果指向的記憶體塊之後沒有足夠的空間,會重新分配size大小的空間,將原有的資料重頭到尾拷貝到新記憶體空間,然後將原空間釋放,最後返回新分配空間的首地址。
注意:
- realloc失敗的時候返回NULL;
- realloc失敗的時候,原來的記憶體空間不改變,不會釋放也不會移動;
- 如果size為0,效果等同於free,只對指標所指記憶體進行釋放;對於二級指標**a realloc時,只會釋放一維,注意使用時謹防記憶體洩漏;
- 傳遞給realloc的指標必須是先前通過malloc、calloc、realloc申請的;
- 當ptr為NULL時,該函式等同於malloc
void TestMemory () { // Malloc int * pTest = ( int*) malloc(10 * sizeof( int)); DoSomething(); if ( pTest != NULL) { free( pTest); pTest = NULL; } // calloc 該函式會將申請的記憶體空間初始化為0 int * pTest1 = ( int*) calloc(10, sizeof( int)); DoSomething(); if ( pTest != NULL) { free( pTest); pTest = NULL; } // rellock,改變原有記憶體空間大小,若不能改變,則將會開闢一段新的記憶體, //將原有記憶體的內容拷貝過去, // 但不會對新開闢的空間進行初始化 int * pTest2 = ( int*) malloc(10 * sizeof( int)); realloc( pTest2, 100*sizeof( int)); free( pTest2); }
以上3個函式使用完後一定要free掉那段空間,否則會引起記憶體洩漏。這在大的專案中是一件很可怕的事情。
【常見的記憶體洩露】
void MemoryLeaks() { // 1、記憶體申請了忘記釋放 int *pTest = (int *)malloc(10*sizeof( int)); assert(NULL != pTest); DoSomething(); // 2、程式邏輯不清,以為釋放了,實際記憶體洩露 int *pTest1 = (int *)malloc(10*sizeof( int)); int *pTest2 = (int *)malloc(10*sizeof( int));DoSomething(); pTest1 = pTest2; free(pTest1); free(pTest2); // 3、程式誤操作,將堆破壞 char *pTest3 = (char *)malloc(5); strcpy(pTest3, "Memory Leaks!"); free(pTest3); // 4、釋放時傳入的地址和申請時的地方不相同 int *pTest4 = (int *)malloc(10*sizeof( int)); assert(NULL != pTest4); pTest4[0] = 0; pTest4++; DoSomething(); free(pTest4); }
【棧上】
使用_alloc(VS)或alloca(gcc)在棧上動態開闢記憶體,棧上開闢的記憶體由編譯器自動維護,不需要使用者顯式釋放。用法同malloc。
以上幾個函式是C語言中的函式,在C++中也可以使用。下面再來看看C++自己的動態記憶體開闢方法:
【new/delete 運算子】
用用new分配空間看起來比C中動態記憶體開闢的方法簡便一些,而且無需自己計算所需記憶體的大小,返回值也無需強制型別轉換。
void Test { int* int* int* () p4 = new int; p5 = new int(3); p6 = new int[3]; // 動態分配4個位元組(1個 int)的空間單個數據 // 動態分配4個位元組(1個 int)的空間並初始化為3 // 動態分配12個位元組(3個 int)的空間 delete p4 ; delete p5 ; delete[] p6 ; }
new和delete、new[]和delete[]一定匹配使用,否則可能出現記憶體洩露甚至崩潰的問題。以上程式碼雖然沒有配對使用,但也不會出錯。但下邊的例子就會出錯了。void Test () { // 以下程式碼沒有匹配使用,會發生什麼?有記憶體洩露嗎?會崩潰嗎? int* p4 = new int; int* p5 = new int(3); int* p6 = new int[3];int* p7 = (int*) malloc(sizeof (int)); delete[] p4 ; delete p5 ; free(p5 ); delete p6 ; delete p7 ; }
用以上註釋中的方法釋放空間時,程式都將會崩潰。當註釋掉test中的解構函式後,即使不配對使用,程式又會正常執行。下面來解釋下這種原因。class test { public: test(){} ~test(){} int i; } int main() { test *p1 = new test; //delete[] p1; test *p2 = new test[10]; //delete p2; //free p2; return 0; }
其實我們用new來申請一段空間時,編譯器會先呼叫operator new函式,然後再呼叫建構函式(如果有的話)進行初始化。其中,在operator new函式中,又呼叫了malloc函式,即operator new是malloc的封裝;用delete來釋放空間,編譯器會先呼叫一次解構函式,然後才呼叫free釋放那段空間。
再來看看new [] 和 delete [],以test *p2 = new test[10];來舉例說明。
如上,編譯器總共開闢了44個位元組,其中後40個位元組用來存放物件,new[]返回的1指標就指向這40個位元組的首地址。前4個位元組存放了物件個數,它的作用先不管,看一看new[]是怎麼做的:
其實new []是對operator new[] 的一個封裝,用new[]來分配空間時,呼叫了operator new[],然後在operator new[]內,將所申請的記憶體空間大小計算出來,例如上邊例子中就是10*sizeof(test),然後在這個基礎上加4,變成了44(位元組),而operator new[]又封裝了operator new,接著又呼叫了operator new。所以現在清楚了吧!真正申請的空間大小多了4位元組。呼叫完operator new[]後,又將返回的指標向後偏移4個位元組,並依次呼叫10次建構函式,完成對物件的初始化,然後才將這個偏移4位元組後的指標返回去。也就是使用者看到的指標了。
再看delete[],它其實封裝了operator delete[] 和free,用delete[]釋放空間時,先根據傳進來指標所指向空間的前4個位元組的內容(即物件的個數,假設為n),呼叫n次解構函式(反著來的,先構造的後析構),然後將這個地址傳遞給operator delete[],operator delete[]封裝了operator delete,它先計算出這段空間的真正首地址,即將傳進來的指標向前偏移4個位元組,然後呼叫operator delete。
看看這張圖,你會更清晰:
現在明白了吧,上邊的
test *p1 = new test; //delete[] p1;
申請了一段空間,實際大小也就是sizeof(test)的大小,然而卻呼叫了delete[]來釋放,這裡變可是會把指標往前偏移4個位元組,所以後邊free的時候自然會出錯!同理,test *p2 = new test[10]; //delete p2; //free p2; 也是類似。而後面我將建構函式註釋掉後,由於沒有了建構函式,編譯器便無需知道呼叫多少次解構函式,也就不會多開闢4個位元組空間用來儲存物件個數,那麼也就不會出錯了。
總結一下:
【new作用】
呼叫operator new分配空間。
呼叫建構函式初始化物件。
【delete作用】
呼叫解構函式清理物件
呼叫operator delete釋放空間
【new[]作用】
呼叫operator new分配空間。
呼叫N次建構函式分別初始化每個物件。
【delete[]作用】
呼叫N次解構函式清理物件。
呼叫operator delete釋放空間。定位new表示式:定位new表示式是在已分配的原始記憶體空間中呼叫建構函式初始化一個物件。
注意:C++中的建構函式是不能顯示呼叫的,這裡只是變相的呼叫了建構函式。
像上面這樣,就完成了對所申請空間的初始化,借用定位new表示式,malloc和free,再加上顯示的呼叫解構函式,可以模擬出new/delete和new[]/delete[]的行為。這裡不在寫了。test *p = new test[10]; new(p) test; new(p + 1) test; //... new(p + 9) test;
【malloc/free和new/delete的區別和聯絡】
- 它們都是動態管理記憶體的入口
- malloc/free是C/C++標準庫的函式,new/delete是C++操作符
- malloc/free只是動態分配記憶體空間/釋放空間。而new/delete除了分配空間還會呼叫建構函式和解構函式進行初始化與清理(清理成員)
- malloc/free需要手動計算型別大小且返回值會void*,new/delete可自己計算型別的大小,返回對應型別的指標
- 對於非內部資料型別的物件而言,光用maloc/free無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行解構函式。由於malloc/free是庫函式而不是運算子,不在編譯器控制權限之內,不能夠把執行建構函式和解構函式的任務強加於malloc/free
- 它們都需要各自配對使用
相關推薦
malloc/calloc/realloc/free與new/delete對比
C動態申請記憶體函式: 【堆上】 函式原型:void *malloc(size_t size); 函式功能:申請size個位元組的記憶體空間,返回該段空間的首地址,該空間裡面的東西是隨機值。 返回值:始終是void*,申請成功,返回空間的首地址,否則返回NULL,所以使用
malloc/free與new/delete的區別與聯系
簡單 指針類型 分配 成了 無法 free pub 之前 tle 相同點:(1)都是申請內存,釋放內存,free和delete可以釋放NULL指針;(2)都必須配對使用,這裏的配對使用,可不能理解為一個new/malloc就對應一個delete/free,而是指在作用域內,
malloc/free 與 new/delete
相同點: 都可用於申請動態記憶體和釋放記憶體 不同點: malloc 和 free 是C/C++ 標準庫函式, new / delete 是 C++ 的運算子 new 自動計算需要分配的空間,而 malloc 需要手工計算所需位元組數 new 是
百度筆試題:malloc/free與new/delete的區別
相同點:都可用於申請動態記憶體和釋放記憶體 不同點: (1)操作物件有所不同。 malloc與free是C++/C 語言的標準庫函式,new/delete 是C++的運算子。對於非內部資料類的物件而言,光用maloc/free 無法滿足動態物件的要求。物件在建立的同時要自動
malloc calloc realloc free的簡單實現
寫在前面:csdn的部落格排版就是shit,祝早日關門大吉 記憶體分配其實是個必修課,應該清楚地知道一個程式在計算機中的記憶體分佈情況,linux程式在記憶體中的分佈情況是這樣的: 當然啦除了知道諸如“堆從低地址向高地址增長棧從高地址從低地址增長”這種東
C動態記憶體分配:(三)malloc/calloc/realloc/free使用注意事項
10、對於realloc不要將返回結果再賦值給原指標,即ptr=realloc(ptr,new_size)是不建議使用的,因為如果記憶體分配失敗,ptr會變為NULL,如果之前沒有將ptr所在地址賦給其他值的話,會發生無法訪問舊記憶體空間的情況,所以建議使用temp=realloc(ptr,new_size)
動態記憶體分配相關的4個函式: malloc calloc realloc free
一、malloc() 引數:分配的位元組數 引用<stdlib.h>標頭檔案 返回一個指標,若記憶體不足,返回一個空指標。 1、函式原型及說明: void *malloc(long NumBytes):該函式分配了NumBytes個位元組,並返回了指向這塊記憶體的指標。如果分配
動態記憶體分配的大家族之malloc calloc realloc free
當我們在宣告陣列時,一般都會用一個常量去定義陣列的長度,但是陣列真正的長度在錄入資料時才知道的,那麼就會存在分配的陣列長度不夠或是長度太長造成浪費等問題,此時,我們就需要用到“動態記憶體分配”。在動態記憶體分配這個大家族中,有malloc(執行動態記憶體的分
alloca/malloc/calloc/realloc/sbrk/new/delete
alloca/malloc/calloc/realloc/sbrk/new/delete 轉載:https://www.xuebuyuan.com/1906334.html C語言跟記憶體分配方式 (1)從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執
C/C++ - malloc/free和new/delete的區分
字節 delete 分別是 自定義 void int eight 構造函數 內存 new/delete與malloc/free的區別主要表現在以下幾個方面: 註意:最主要的區別,new/delete是運算符,而malloc/free是函數 (1)、new能夠自動計算
【C語言】記憶體分配函式malloc/ calloc/ realloc及記憶體釋放free
前言: 記憶體區域劃分與分配: 1、棧區(stack)——程式執行時由編譯器自動分配,存放函式的引數值,區域性變數的值等,程式結束時由編譯器自動釋放。 2、堆區(heap) —— 在記憶體開闢另一塊儲存區域。一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可
malloc/free和new/delete的區別
malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子
malloc,free和new delete的區別
1.malloc和free是庫函式,以位元組為單位申請記憶體 2.new和delete是關鍵字,以型別為單位申請記憶體 3.malloc和free單純的對記憶體進行申請與釋放 4.對於基本型別new關鍵字會對記憶體進行初始化 5.對於類型別new和delete還負責建
C++細節 C++中的malloc/free ,new/delete
首先,malloc/free 是函式,new/delete是一個操作符 下面看一下malloc,free,realloc函式原型 (引用自C++ reference) malloc/free ,calloc,realloc malloc void* malloc
malloc/free和new/delete 的詳解
1.malloc和free:
malloc/free And new/delete
1. malloc/free是C++/C語言的標準庫函式,new/delete是C++的運算子。它們都可用於申請動態記憶體和釋放記憶體。2. 對於非內部資料型別的物件而言,光用malloc/free無法滿足動態物件的要求。物件在建立的時候要自動執行建構函式,物件在消亡之前要自動執行解構函式。由
C/C++ 動態儲存分配 malloc calloc realloc函式的用法與區別
一、前言 動態儲存分配函式標頭檔案malloc.h(ANSI標準建議使用stdlib.h,但很多編譯器可能不支援),提供許多函式來實現對記憶體區域的堆上記憶體進行管理,主要有: void *
常見動態記憶體分配malloc()/free()、new/delete使用方法及常見錯誤
1.動態記憶體分配的幾種方式 ①從靜態儲存區分配記憶體,記憶體在編譯時已經分配好了,這塊記憶體在整個程式執行期間都存在,比如全域性變數 ②從棧上分配記憶體,函式體結束時,棧記憶體自動銷燬,比如區域性變數 ③從堆上開闢記憶體,比如malloc()/ne
淺談 malloc/free 和 new/delete
malloc 和 free 是 C 語言中的函式,也可以用在 C++ 中,但在 C++ 中卻視為不安全的記憶體操作。而 new 和 delete 是 C++ 中的兩個運算子,完全可以替代 malloc/free 完成記憶體的操作,且為安全的記憶體操作。在C++
C++中malloc/free和new/delete的區別---補充(15)《Effective C++》
1、C++中既然有了new/delete為什麼還有還存在malloc/free呢? 1)malloc/free作為C/C++語言中的庫函式,而new/delete是C++中的運算子而已,因此C++編譯器可以強制使new/delete運算子進行建構函式和解構函式