日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入浅出之动态内存(new,malloc深度分析)

發布時間:2024/9/27 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出之动态内存(new,malloc深度分析) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

void GetMemory(char *p)

{

p = (char *)malloc(100);

}

void Test(void)

{

char *str = NULL;

GetMemory(str);??

strcpy(str, "hello world");

printf(str);

}

請問運行Test函數會有什么樣的結果?

答:程序崩潰。

因為GetMemory并不能傳遞動態內存,

Test函數中的?str一直都是?NULL。

strcpy(str, "hello world");將使程序崩潰。

char *GetMemory(void)

{??

char p[] = "hello world";

return p;

}

void Test(void)

{

char *str = NULL;

str = GetMemory();???

printf(str);

}

請問運行Test函數會有什么樣的結果?

答:可能是亂碼。

因為GetMemory返回的是指向“棧內存”的指針,該指針的地址不是?NULL,但其原現的內容已經被清除,新內容不可知。

void GetMemory2(char **p, int num)

{

*p = (char *)malloc(num);

}

void Test(void)

{

char *str = NULL;

GetMemory(&str, 100);

strcpy(str, "hello");??

printf(str);???

}

請問運行Test函數會有什么樣的結果?

答:

(1)能夠輸出hello

(2)內存泄漏

void Test(void)

{

char *str = (char *) malloc(100);

????strcpy(str,?“hello”);

????free(str);????

????if(str != NULL)

????{

?????strcpy(str,?“world”);

printf(str);

}

}

請問運行Test函數會有什么樣的結果?

答:篡改動態內存區的內容,后果難以預料,非常危險。

因為free(str);之后,str成為野指針,

if(str != NULL)語句不起作用。

1.? 關鍵字、操作符與庫函數

  • 關鍵字是編譯器保留的文字,不能被用戶拿來重新聲明,像const, new, if等等
  • 操作符必須要有操作對象,操作符本質上可以視為編譯器內置的基礎的函數。操作符在c++中,可以被重載(除了部分例外,比如 . :: sizeof)。
  • 庫函數是編寫在編譯器頭文件庫里,要包含頭文件才能調用的封裝函數。

2.?自由存儲區與堆的區別

堆(heap)是C語言和操作系統的術語。堆是操作系統所維護的一塊特殊內存,它提供了動態分配的功能,當運行程序調用malloc()時就會從中分配,稍后調用free可把內存交還。而自由存儲是C++中通過new和delete動態分配和釋放對象的抽象概念,通過new來申請的內存區域可稱為自由存儲區。基本上,所有的C++編譯器默認使用堆來實現自由存儲,也即是缺省的全局運算符new和delete也許會按照malloc和free的方式來被實現,這時藉由new運算符分配的對象,說它在堆上也對,說它在自由存儲區上也正確。但程序員也可以通過重載操作符,改用其他內存來實現自由存儲,例如全局變量做的對象池,這時自由存儲區就區別于堆了。我們所需要記住的就是:

堆是操作系統維護的一塊內存,而自由存儲是C++中通過new與delete動態分配和釋放對象的抽象概念。堆與自由存儲區并不等價。?

3. 野指針

野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)指針變量在定義時如果未初始化,其值是隨機的,指針變量的值是別的變量的地址,意味著指針指向了一個地址是不確定的變量,此時去解引用就是去訪問了一個不確定的地址,所以結果是不可知的。?

4. malloc和new區別

在C++中,申請動態內存與釋放動態內存用new/delete 與 malloc/free都可以,new/malloc申請動態內存,操作系統無法自動回收,需要對應的delete/free釋放空間。

  • malloc/free 是c語言中的庫函數,需要頭文件支持;而new/delete 是c++中的關鍵字
  • 使用new操作符時編譯器會根據類型信息自行計算所需要的內存,而malloc需要顯式指出所需內存的尺寸
int *p = new int[2]; int *q = (int *)malloc(2*sizeof(int));
  • malloc內存分配成功時,返回的是void*,需要轉換成所需要的類型

    new內存分配成功時,返回的是對象類型的指針,類型嚴格與對象匹配,無須進行類型轉換,故new是符合類型安全性的操作符

    free釋放內存的時候需要的是void* 類型的參數

    delete釋放內存的時候需要使用具體類型的指針

  • new操作符在分配失敗的時候會拋出bac_alloc異常

    malloc在分配內存失敗時返回NULL

  • new操作符從自由存儲區(free store)上為對象動態分配內存空間,允許重載new/delete操作符

    malloc函數從堆上動態分配內存,malloc不允許被重載

  • new會先調用operator new函數,申請足夠的內存(通常底層使用malloc實現)。然后調用類型的構造函數,初始化成員變量,最后返回自定義類型指針。delete先調用析構函數,然后調用operator delete函數釋放內存(通常底層使用free實現)。

    malloc/free是庫函數,只能動態的申請和釋放內存,無法強制要求其做自定義類型對象構造和析構工作。

5.?new()和new[]的區別

  • ? new()創建一個對象
  • ? new[]創建一個動態數組
  • 釋放方法也不一樣,new()對應delete,new[]對應delete[]
char *pc = new char('a'); //開辟一個內存單元,并用括號里的初始化 char *pca = new char[15]; //開辟一個數組 釋放內存的方法也不一樣: delete pc; delete []pc;

6.?delete和delete[]的區別

?new 分配的單個對象的內存空間的時候用 delete,回收用 new[] 分配的一組對象的內存空間的時候用 delete[],其實要分基本數據類型和自定義數據類型。

  • 基本數據類型

int *a = new int[10];...delete a; // 方式1delete [ ] a; //方式2

基本的數據類型對象沒有析構函數,并且new 在分配內存時會記錄分配的空間大小,則delete時能正確釋放內存,無需調用析構函數釋放其余指針。因此兩種方式均可。

  • 自定義數據類型?
#include <iostream>; using namespace std;class T { public:T() { cout << "constructor" << endl; }~T() { cout << "destructor" << endl; } };int main() {const int NUM = 3;T* p1 = new T[NUM];cout << hex << p1 << endl; //輸出P1的地址// delete[] p1;delete p1;cout << endl;T* p2 = new T[NUM];cout << p2 << endl; //輸出P2的地址delete[] p2;return 0; }

從運行結果中我們可以看出,delete p1 在回收空間的過程中,只有 p1[0] 這個對象調用了析構函數,其它對象如 p1[1]、p1[2] 等都沒有調用自身的析構函數,這就是問題的癥結所在。如果用 delete[],則在回收空間之前所有對象都會首先調用自己的析構函數。
????基本類型的對象沒有析構函數,所以回收基本類型組成的數組空間用 delete 和 delete[] 都是應該可以的;但是對于類對象數組,只能用 delete[]。對于 new 的單個對象,只能用 delete 不能用 delete[] 回收空間。
????所以一個簡單的使用原則就是:new 和 delete、new[] 和 delete[] 對應使用。?

?7. delete或者free之要將指針指為NULL

delete和free被調用后,內存不會立即回收,指針也不會指向空,delete或free僅僅是告訴操作系統,這一塊內存被釋放了,可以用作其他用途。但是由于沒有重新對這塊內存進行寫操作,所以內存中的變量數值并沒有發生變化,這時候就會出現野指針的情況。因此,釋放完內存后,應該把指針指向NULL
?

#include <iostream> using namespace std;int main() {int *p = new int;*p = 3;cout << *p << endl;cout << p << endl;delete p;cout << *p << endl;cout << p << endl;return 0; }

?delete之后,p指向的地址并沒有發生變化,而地址里面的內容卻成了隨機數,那么,我們可以得到下面這條結論

我們在刪除一個指針之后,編譯器只會釋放該指針所指向的內存空間,而不會刪除這個指針本身。
此時p也就成為一個野指針

#include <iostream> using namespace std;int main() {int *p = new int;delete p;p = NULL;delete p; }

如果不加p=NULL;程序運行時就會掛掉,加上就不會了,對NULL空間多次釋放時沒有問題的,但是不是NULL就不可以,因為這段空間已經釋放掉,不屬于本程序,不能夠取隨意的釋放。

8. 使用原則

  • 原則1: 優先使用new,delete
  • 原則2: 要new和delete配對,new[]和delete [],malloc和free配對使用
  • 原則3: free和delte后指針一定賦予NULL,防止成為野指針

9.C++智能指針如何指向數組

智能指針在幫助C++程序員管理動態內存方面可謂神兵利器,但是在有些情況下我們想要對數組進行動態內存管理就會發現一個問題 咦?shared_ptr 在默認情況下是不能指向數組的,那是為什么呢。

原因是因為我們的 shared_ptr 默認的刪除器是使用 Delete 對智能指針中的對象進行刪除,而 delete 要求 new 時是單一指針 Delete時也應該是指針 new時是數組 delete 也應該用數組類型去delete

shared_ptr
所以我們如果想讓我們的 share_ptr 去指向指針 我們只需要去使用一個可調用對象即可 在這種情況下比較常用的函數或者lambda表達式均可

bool del(int *p){delete [] p; }shared_ptr<int> shared(new int[100],del);//使用函數shared_ptr<int> ptr(new int[100], [](int *p){delete [] p;});//使用lambda表達式


因為智能指針沒有重載下標運算符 意味著我們不能想數組那樣去使用這個指針 那怎么樣才可以使用呢

shared_ptr 有一個函數可以返回當前智能指針的內置指針的函數 就是成員函數get() 但是我們要注意當智能指針指針已經釋放內存以后,get得到的指針就成了空懸指針
有一點需要注意 在我們得到get返回的指針以后,智能指針對象的引用計數其實并沒有增加

?get() const noexcept{ return _M_ptr; }


這是get的函數定義

但是如果我們delete從get得到的指針 并不會出現多次delete的錯誤,現在還不是很理解為什么

我們該如何使用從get中得到的指針呢 其實很簡單,就是我們一般的指針操作即可

? ? auto x = ptr.get();cout << *(x+i) << endl;

注意!!!
其實只是C++11 中不支持而已 C++17中已經支持

unique_ptr
相比與shared_ptr unique_ptr對于動態數組的管理就輕松多了 我們只需要直接使用即可

unique_ptr<int[]>unique(new int[100]);


而且unique_ptr是重載了下標運算符的,意味著我們可以方便把其當數組一樣使用

Boost C++庫
著名的Boost庫其實是支持指向數組的,使用方法與unique_ptr差不多

Boost庫是什么?

類名為boost::shared_array,定義在<boost/shared_ptr.hpp>

boost::shared_array<int> arr(new int[100]);?


?

參考文獻:

  • 關鍵字、操作符與庫函數01
  • 自由存儲區和堆的區別
  • new 和 malloc free 和 delete 的區別
  • C++中的delete和delete[ ]的區別
  • C++中delete和delete[]的區別 - charley_yang - 博客園
  • C/C++動態內存管理malloc/new、free/delete的異同
  • delete一個指針之后,要記得設置為NULL
  • delete或者free之后為什么要將指針指為NULL
  • C++智能指針如何指向數組

  • 總結

    以上是生活随笔為你收集整理的深入浅出之动态内存(new,malloc深度分析)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。