【C++初階】C/C++內存管理
🥕個人主頁:開敲🍉
🔥所屬專欄:C++🥭
🌼文章目錄🌼
1. C/C++內存分布
2. C語言中動態內存管理方式:malloc/calloc/realloc/free
3. C++內存管理方式
? ? 3.1 new/delete操作內置類型
? ? 3.2 new和delete操作自定義類型
4. operator new和operator delete函數
? ? 4.1 operator和operator delete
5. new和delete的實現原理
? ? 5.1 內置類型
? ? 5.2 自定義類型
6. malloc/free和new/delete的區別
1. C/C++內存分布
? 我們來看下面的一段代碼和相關問題。
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);}
1. 選擇題
選項: A.棧 B.堆 C.數據段(靜態區) D.代碼段(常量區)
globalVar在哪里?____
staticGlobalVar在哪里?____
staticVar在哪里?____
localVar在哪里?____
num1 在哪里?____
char2在哪里?____
*char2在哪里?___
pChar3在哪里?____
*pChar3在哪里?____
ptr1在哪里?____
*ptr1在哪里?____
2. 填空題??sizeof(num1) = ____;??
??sizeof(char2) = ____;???strlen(char2) = ____;
??sizeof(pChar3) = ____;???strlen(pChar3) = ____;
??sizeof(ptr1) = ____;
選擇題答案:C、C、C、A、A? ? ? ? ?A、A、A、D、A、B
第一題:globalVar是全局變量,存放于數據段(靜態區)
第二題:staticGlobalVar是靜態變量,存放于數據段(靜態區)
第三題:staticVar是靜態變量,存放于數據段(靜態區)
第四題:localVar是局部變量,存放于棧區
第五題:num1是數組首元素地址,局部變量,存放于棧區
第六題:char2是數組首元素地址,局部變量,存放于棧區
第七題:因為char2是一個數組,*char2就是常量字符串的第一個字符,字符串存于代碼段(常量區),*char2是將存于常量區的常量字符串的第一個字符拷貝存儲到數組中,因此*char2拿到的是存于數組中,也就是存于棧區的數據
第八題:pChar3是指針,指向常量字符串首元素地址,地址存放于棧區
第九題:*pChar3拿到的是存于代碼段(常量區)的字符串的首元素,存于代碼段(常量區)
第十題:ptr1是指針,指向動態開辟的空間首地址,地址存放于棧區
第十一題:*ptr1拿到的是動態開辟的空間中存儲的元素,動態開辟的空間存放于堆區
填空題答案:40、5、4、4、4、4
第一題:sizeof(num1)中的num1代表整個數組,整個數組大小就是10*4=40字節
第二題:sizeof(char2)計算的是指針類型的大小,32位機器下指針大小為4個字節,64位機器下指針大小為8個字節
第三題:strlen(char2)計算的是字符串長度,遇到'\0'停止
第四題:sizeof(pChar3)計算的也是指針類型的大小
第五題:strlen(pChar3)計算的是字符串長度,遇到'\0'停止
第六題:sizeof(ptr1)計算的也是指針類型的大小
? 說明:
① 棧又叫堆棧--非靜態局部變量/函數參數/返回值等等,棧是向下增長的。
②?堆用于程序運行時動態內存分配,堆是可以上增長的。
④?數據段--存儲全局數據和靜態數據。
⑤?代碼段--可執行的代碼/只讀常量。
2. C語言中動態內存管理方式:malloc/calloc/realloc/free
? C語言動態開辟內存的方式:
?? ?int* arr1 = (int*)malloc(sizeof(int) * 4);
? ? int* arr2 = (int*)calloc(10,sizeof(int));
?? ?int* arr3?= (int*)realloc(arr1, sizeof(int) * 40);
? 這里我們用realloc對arr1進行增容時,如果是在另外的地方開辟40個字節的空間,realloc會幫我們完成 釋放arr1原來的空間——將arr1指向arr3所在空間的操作。因此無需我們手動free(arr1)。
3. C++內存管理方式
??C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過new和delete操作符進行動態內存管理。
? ? 3.1 new/delete操作內置類型
?? ?//動態申請一個int大小的空間
?? ?int* a1 = new int;?? ?//動態申請一個int的空間,并將值初始化為10
?? ?int* a2 = new int(10);?? ?//動態申請int類型的數組,長度為10
?? ?int* a3 = new int[10];
?? ?a3[0] = 1;
?? ?cout << *a1 << endl;
?? ?cout << *a3 << endl;
?? ?cout << a3[0] << endl;? ? //釋放a3動態開辟的空間
? ??delete a1;
? ? delete a2;
? ??delete[] a3;
? ? //注:動態開辟的空間delete后必須加上[],否則會報錯
? ? 3.2 new和delete操作自定義類型
? 從上圖可以看出,使用C語言的malloc對類類型開辟空間和使用free釋放空間時,并不會調用類中的析構造函數和析構函數;而用C++的new對類類型開辟空間和使用delete釋放空間時,會調用類中的構造函數和析構函數。
? 而對于int這些內置類型,不管是malloc和free還是new和delete,都是一樣的效果。
??注:對于類類型的數組開辟,釋放空間時同樣需要在delete后加上[],否則會報錯
4. operator new和operator delete函數
? ? 4.1 operator和operator delete
??new和delete是用戶進行動態內存申請和釋放的操作符,operator new 和operator delete是
系統提供的全局函數,new在底層調用operator new全局函數來申請空間,delete在底層通過
operator delete全局函數來釋放空間。
? 下面是系統 operator new和operator delete函數底層代碼:
/*
operator new:該函數實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間
失敗,嘗試執行空 間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否
則拋異常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
?????????// try to allocate size bytes
?????????void *p;
?????????while ((p = malloc(size)) == 0)
?????????if (_callnewh(size) == 0)
????????{
????????????????// report no memory
????????????????// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常
????????????????static const std::bad_alloc nomem;
????????????????_RAISE(nomem);????????}
}????????return (p);
}
?/*
operator delete: 該函數最終是通過free來釋放空間的
*/
void operator delete(void *pUserData)
{
????????_CrtMemBlockHeader * pHead;
? ? ? ? RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
????????if (pUserData == NULL)
????????return;/* get a pointer to memory block header */
_mlock(_HEAP_LOCK);
__TRY/* block other threads */
pHead = pHdr(pUserData);
/* verify block type */
????????_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
????????_free_dbg( pUserData, pHead->nBlockUse );
????????__FINALLY
_munlock(_HEAP_LOCK);
__END_TRY_FINALLY/* release other threads */ ????????return;
}/*
free的實現
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
? 不需要明白代碼邏輯,只需要知道在調用new和delete時,實際上調用的是operator new和operator delete函數,同時operator new實際也是通過malloc來申請空間的,不同的是,C語言malloc失敗是直接返回NULL,而new失敗是拋異常,同時對于類類型對象還會調用其構造函數;operator delete最終也是通過free來釋放空間的是,不同的是對于類類型,還會調用析構函數。
5. new和delete的實現原理
? ? 5.1 內置類型
? 如果是內置類型,new和delete與malloc和free基本是相同的,不同的地方在于:new在申請空間失敗時是拋異常,而malloc申請空間失敗時是返回NULL。
? ? 5.2 自定義類型
① new的原理:
? ? 1. 底層是調用operator new函數申請空間,這是一個重載運算符
? ? 2. 在申請類類型的空間時,調用對象的構造函數完成對對象的構造
② new[N]的原理:
? ? 1. 調用operator new[]函數,operator new[]調用operator new函數,實際上最終也是調用operator new函數完成N個對象的申請
? ? 2. 申請類類型對象時,調用N次構造函數
③ delete的原理:
? ? ?1. 釋放類類型的空間時,首先調用對象的析構函數,對動態申請的空間進行釋放
? ? ?2. 底層調用operator delete函數釋放對象的空間,是一個重載運算符?
④ delete[]的原理:
? ? ?1. 釋放類類型對象時,調用N次析構函數
? ? ?2. 調用operator delete[]函數,operator delete[]調用operator delete函數,實際上最終也是調用operator delete函數完成對N個對象空間的釋放
6. malloc/free和new/delete的區別
??malloc/free和new/delete的共同點是:都是從堆上申請空間,并且需要用戶手動釋放。
? 不同的地方是:
①?malloc和free是函數,new和delete是操作符
②?malloc申請的空間不會初始化(calloc可以),new可以初始化
③?malloc申請空間時,需要手動計算空間大小并傳遞,new只需在其后跟上空間的類型即可,
如果是多個對象,[]中指定對象個數即可
④?malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的類型
⑤?malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需
要捕獲異常
⑥?申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數與析構函數,而new
在申請空間后會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成
空間中資源的清理釋放
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 創作不易,點個贊唄,蟹蟹啦~