一文解决new/delete与malloc/free相关问题:区别?注意事项?使用方式?
目錄
一、內存分配模型
1.1 先看內存的分布狀況
1.2?動態內存分配
1.3 C語言中分配內存的方式
1.4 C++中動態分配內存的方式
二、new和malloc的區別
2.1 屬性
2.2 參數
2.3 返回類型
2.4?分配失敗
2.5 自定義類型
2.6 重載
2.7 內存區域
2.8?分配內存時內存不足
2.9?new與malloc是否可以相互調用
三、與new、malloc相關的問題解答
3.1 為什么有了malloc/free為什么還要new/delete
3.2 為什么new/delete的功能完全覆蓋了malloc/free,C++還在用malloc/free
3.3 delete與delete []的區別
3.4 動態內存分配后的指針與指針指向的內存
3.5 零值指針和NULL指針
參考鏈接
網上相關的說法都很多,但不夠系統,而且存在于八股文,本文特意整理了一下,并進行一些補充,歡迎指正。
一、內存分配模型
1.1 先看內存的分布狀況
一個由C/C++編譯的程序占用的內存分為以下幾個部分:
1、棧區(stack)— 由編譯器自動分配釋放 ,存放為運行函數而分配的局部變量、函數參數、返回數據、返回地址等。其操作方式類似于數據結構中的棧。
2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。分配方式類似于鏈表。
3、全局區(靜態區)(static)—存放全局變量、靜態數據、常量。程序結束后由系統釋放。
4、文字常量區 —常量字符串就是放在這里的。 程序結束后由系統釋放。
5、程序代碼區—存放函數體(類成員函數和全局函數)的二進制代碼。
1.2?動態內存分配
在執行程序的過程中動態的分配或者回收存儲空間的分配內存的方法。
例如:當我們在定義一個數組時,必須要用一個常量來確定在編譯時分配多大的空間。但是在真正使用數組時,我們才會知道我們需要多少內存空間,所以我們要根據程序的需要即時分配,這就牽扯到內存的動態開辟。
1.3 C語言中分配內存的方式
malloc、calloc、realloc、free
malloc:
void *malloc(unsigned int size)
開辟一塊長度為size的連續內存空間,返回類型為void類型的指針。在使用malloc開辟一段空間時,void*要顯示的轉換為所需要的類型,如果開辟失敗,則返回NULL指針。
calloc
void* calloc (size_t num, size_t size);
開辟一塊num個大小為size的連續空間,并將每一塊空間初始化為0。
realloc
void *realloc(void *ptr,size_t size);
將內存地址為ptr的一段空間的大小調整為size大小。
如果ptr這段空間后面有足夠的空間,就直接追加上來
如果ptr后面的空間不足,則在堆上重新開辟一塊合適大小的連續空間,將原有數據拷貝到新的內存空間中,釋放掉原來的內存,最后返回的則是新地址。
free
void free (void* ptr);
free函數是來釋放動態開辟的內存的。
malloc和free要配套使用,如果沒有free則會造成內存泄漏。
本文作者:https://www.zhihu.com/people/san-hao-bai-du-ren-79
(由于文章總是被三無號到處復制發布,選擇這種方式插入原文鏈接影響閱讀實在抱歉!)
本文原文鏈接:https://blog.csdn.net/qq_41687938/article/details/118421508
malloc()從哪里獲取的內存?
動態開辟的從堆里獲取空間。就是說malloc函數返回的指針是指向堆里的一塊內存。操作系統中有一個記錄空閑內存地址的鏈表,當操作系統收到程序的申請時,就會遍歷鏈表
1.4 C++中動態分配內存的方式
new、delete
new
new運算返回所分配內存單元的起始地址,所以需要把返回值保存在一個指針變量中。若分配不成功,返回NULL,并拋出異常。
new沒有為創建的對象命名,只能通過指針去訪問對象或者數組。
delete
delete <指針變量>
delete []<動態分配的數組名>
new和delete必須配對使用。
雖然程序結束后系統會自動釋放程序和其中數據所占的內存空間,但是為了在程序運行過程中能夠重復使用有限的內存資源,防止系統產生內存泄漏,還是應該即時釋放不需要的動態分配的內存單元,以便系統能隨時對該內存單元進行分配。
delete釋放內存,只是銷毀內存上的對象,但是指針仍然存在,仍然指向原來的內存,保存原來空間的地址。所以我們應該在釋放之后將指針置空,以避免后面不小心解引用造成問題。
示例:
char *pBuffer = new char[100]; int *pNum = new int(100);delete pNum; delete []pBuffer;?//對數組的處理:
A * ptr = new A[10];//分配10個A對象 delete [] ptr; int * ptr = (int *) malloc( sizeof(int) * 10);//分配一個10個int元素的數組 free(ptr);二、new和malloc的區別
2.1 屬性
C與C++動態管理內存的方式不一樣,C是使用malloc/free函數,而C++除此之外還有new/delete關鍵字。
new/delete是C++關鍵字,既是運算符也是關鍵字,需要編譯器支持。malloc/free是庫函數,需要頭文件支持。
2.2 參數
使用new操作符申請內存分配時無須指定內存塊的大小,編譯器會根據類型信息自行計算。而malloc則需要顯式地指出所需內存的尺寸。
2.3 返回類型
new操作符內存分配成功時,返回的是對象類型的指針,類型嚴格與對象匹配,無須進行類型轉換,故new是符合類型安全性的操作符。而malloc內存分配成功則是返回void * ,需要通過強制類型轉換將void*指針轉換成我們需要的類型。
2.4?分配失敗
new內存分配失敗時,會拋出bac_alloc異常。malloc分配內存失敗時返回NULL。
try {int *a = new int(); } catch (bad_alloc) {... }2.5 自定義類型
new會先調用operator new函數,申請足夠的內存(通常底層使用malloc實現)。然后調用類型的構造函數,初始化成員變量,最后返回自定義類型指針。delete先調用析構函數,然后調用operator delete函數釋放內存(通常底層使用free實現)。
malloc/free是庫函數,只能動態的申請和釋放內存,無法強制要求其做自定義類型對象構造和析構工作。
使用new操作符來分配對象內存時會經歷三個步驟:
第一步:調用operator new 函數(對于數組是operator new[])分配一塊足夠大的,原始的,未命名的內存空間以便存儲特定類型的對象。
第二步:編譯器運行相應的構造函數以構造對象,并為其傳入初值。
第三步:對象構造完成后,返回一個指向該對象的指針。
使用delete操作符來釋放對象內存時會經歷兩個步驟:
第一步:調用對象的析構函數。
第二步:編譯器調用operator delete(或operator delete[])函數釋放內存空間。
總之來說,new/delete會調用對象的構造函數/析構函數以完成對象的構造/析構;而malloc則不會。
2.6 重載
C++允許重載new/delete操作符,特別的,布局new的就不需要為對象分配內存,而是指定了一個地址作為內存起始區域,new在這段內存上為對象調用構造函數完成初始化工作,并返回此地址。而malloc不允許重載。
使用new操作符分配內存,編譯器會幫我們轉化成調用operator new()函數,里面再調用全局的operator new()函數,繼而調用malloc()來分配內存,實際上new關鍵字是不能夠重載的,能夠被重載的是operator new()這個函數。delete關鍵字也一樣。
operator new /operator delete的實現可以基于malloc,而malloc的實現不可以去調用new。
2.7 內存區域
new操作符從自由存儲區(free store)上為對象動態分配內存空間,而malloc函數從堆上動態分配內存。自由存儲區是C++基于new操作符的一個抽象概念,凡是通過new操作符進行內存申請,該內存即為自由存儲區。而堆是操作系統中的術語,是操作系統所維護的一塊特殊內存,用于程序的內存動態分配,C語言使用malloc從堆上分配內存,使用free釋放已分配的對應內存。自由存儲區不等于堆,如上所述,布局new就可以不位于堆中。
本文作者:https://www.zhihu.com/people/san-hao-bai-du-ren-79
(由于文章總是被三無號到處復制發布,選擇這種方式插入原文鏈接影響閱讀實在抱歉!)
本文原文鏈接:https://blog.csdn.net/qq_41687938/article/details/118421508
堆是一個實際的區域,而自由存儲區是一個更上層的概念。通常new確實是在堆上申請內存,但是程序員可以自己重載new操作符,使用其他內存來實現自由存儲(這并不常見)。另外,c++ primer plus這本書上有提到布局new,可以為對象在棧上分配內存。總的來說,自由存儲區是new申請的區間的概念。
2.8?分配內存時內存不足
malloc動態分配內存后,如果不夠用可以使用realloc函數重新分配實現內存的擴充;而new則沒有這樣的操作;
2.9?new與malloc是否可以相互調用
operator new /operator delete的實現可以基于malloc,而malloc的實現不可以去調用new。
總結區別如下表
三、與new、malloc相關的問題解答
3.1 為什么有了malloc/free為什么還要new/delete
(1)因為分配內存的對象不一樣,即動態對象與內部數據類型
對于非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由于malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于malloc/free。
因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。
不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由于內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。
總結來說就是,malloc是面向內存的,你要開多大,就給你開多大,開了就不管了。new是面向對象的,根據你指定的數據類型來申請對應的空間,并且能夠直接內部調用構造函數生成對象。
3.2 為什么new/delete的功能完全覆蓋了malloc/free,C++還在用malloc/free
因為C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。
如果用free釋放“new創建的動態對象”,那么該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內存”,結果也會導致程序出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。
3.3 delete與delete []的區別
delete是回收new開辟出的單個對象指針指向的內存。
delete[]是回收new [] 開辟出的對象數組指針指向的內存。
new[]開辟數組空間要多出4個字節來存放數組大小。
delete []要與new []要配套使用
本文作者:https://www.zhihu.com/people/san-hao-bai-du-ren-79
(由于文章總是被三無號到處復制發布,選擇這種方式插入原文鏈接影響閱讀實在抱歉!)
本文原文鏈接:https://blog.csdn.net/qq_41687938/article/details/118421508
3.4 動態內存分配后的指針與指針指向的內存
如果你在函數上面定義了一個指針變量,然后在這個函數里申請了一塊動態分配的內存讓指針指向它。實際上,這個指針的地址是在棧上,但是它所指向的內容卻是在堆上面。這一點要注意!所以,在一個函數里申請了空間后,比如:
void Function(void)? {?char *p = (char *)malloc(100 * sizeof(char));? }
千萬不要認為函數返回,函數所在的棧被銷毀指針也跟著銷毀,申請的內存也就一樣跟著銷毀了。這是錯誤的。因為申請的內存在堆上,除非程序員手動釋放,否則要等到程序結束釋放所有內存才會釋放它們,跟函數是否結束沒有關系。也就是函數所在的棧被銷毀跟堆完全沒有關系。所以,忠告就是:使用完不再需要記得釋放動態分配的內存!在該部分程序退出之前釋放內存并立即給P賦0值(NULL)。另一個辦法是保證P在沒有初始化之前,將不再被使用。
3.5 零值指針和NULL指針
零值指針,是值是0的指針,可以是任何一種指針類型,可以是通用變體類型void*也可以是char*,int*等等。
空指針,其實空指針只是一種編程概念,就如一個容器可能有空和非空兩種基本狀態,而在非空時可能里面存儲了一個數值是0,因此空指針是人為認為的指針不提供任何地址訊息。
參考鏈接
https://blog.csdn.net/nie19940803/article/details/76358673
https://blog.csdn.net/wudikua123/article/details/84215019
https://blog.csdn.net/qq_40840459/article/details/81268252
總結
以上是生活随笔為你收集整理的一文解决new/delete与malloc/free相关问题:区别?注意事项?使用方式?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python turtle 椭圆_【py
- 下一篇: delphi控件切图界面闪烁_一份最详尽