1、內存的簡要了解c++
說到內存,不少人應該都多多少少有點了解了,咱們在這再稍微多說幾句:編程
通常咱們能夠把內存理解爲三個部分:靜態區,棧,堆。有些朋友搞不清到底什麼是棧什麼是堆,堆棧有多人會認爲是堆和棧,兩個放在一塊。其實否則,其中咱們口中講的堆棧就是棧,而不是堆。堆的英文是heap ;棧的英文是stack(也翻譯爲堆棧)。函數
存儲內容:spa
靜態區:保存自動全局變量和static變量(包括static全局和局部變量)。靜態區的內容在整個程序的生命週期內都存在,有編譯器在編譯的時候分配(數據段(存儲全局數據和靜態數據)和代碼段(可執行的代碼/只讀常量))。翻譯
棧:保存局部變量。棧上的內容只在函數範圍內存在,當函數運行結束的時候,這些內容也會自動銷燬。其特色是效率高可是空間大小有限。3d
堆:由malloc系列函數或者new操做符分配的內存。其生命週期由free和delete決定。在沒有釋放以前一直存在,直到函數結束。其特色是使用靈活,空間比較大,但容易出錯。指針
2、malloc、calloc、realloccode
三者的簡單對比:對象
malloc 函數原型:(void*)malloc(unsigned size);(字節數)blog
malloc函數在內存中開闢的是一塊連續的空間,size是所須要空間的長度,開闢的大小爲size*參數類型,開闢完以後返回這塊空間的首地址。
calloc 函數原型:void* calloc(size_t numElements, size_t sizeOfElements);(元素的個數, 單個元素的字節數)
和malloc類似,它也是開闢一塊連續的空間,空間的大小爲:元素的個數*單個元素的字節數。
realloc 函數原型:void* realloc(void* ptr, unsigned newsize);(地址,字節數)
給一個已經分配地址的指針從新分配空間,參數ptr爲原有的空間指針,newsize爲從新申請的地址長度。它與malloc的區別就是若是你給的指針是NULL,那麼你使用的就是malloc,若是你給出的指針是一個已經分配了地址的指針(ptr),那麼你使用的就是realloc。
區別:
(1)函數malloc不能初始化所分配的空間,而函數calloc能,也就是說,若是由malloc函數分配的空間原來沒有被分配過,則其中每一位均可能是0;反之,若是這一塊數據塊原來被分配過,那裏面可能遺留着各類各樣的數據。因此,當你在使用malloc開闢一塊新空間的時候,要從新初始化那一塊空間(通常調用memset函數來初始化空間)。不然在屢次釋放、開闢以後,可能會出現使用錯誤。
(2)calloc函數會將所分配的內存空間中的每一位都初始化爲0(這也是它和malloc的主要不一樣處之一)。也就是說,若是你是爲字符類或者整形類的元素分配空間,那麼這些元素會保證被初始化爲0;若是你是爲指針類函數分配內存,那麼這些元素都會被初始化爲空指針。
(3)malloc向系統申請size個字節的空間,申請完以後返回的是這個空間的首地址,類型爲void*,而void*表示未肯定的類型,在c/c++中void*能夠被強轉成任意類型的指針。
(4)realloc能夠對給定的指針所指向的空間進行擴大或者縮小,不管是擴大仍是縮小,原有內存中的內容將保持不變(若是對於縮小以後的空間,被縮小的那部分空間內的數據仍是會丟失)。realloc並不保證調整後的內存空間和原來的內存空間保持同一個地址。相反,realloc指針極可能指向一個新的地址。
(5)realloc是從堆上分配空間的,但當你進行擴大的時候,realloc會試圖從堆上現存的數據後面的那些字節中獲取附加的字節,若是能知足,就恰好。但若是後面的字節數不夠,其就會使用堆上第一個有足夠大小的自由塊,而後將現存的數據拷貝到新的位置,將老塊放回到堆上。在這個過程當中,數據會被移動。也就是說,當你使用realloc的時候,數據可能被移動。
3、有關malloc的一些擴展(選自《高質量c/c++編程指南(林銳)》)
malloc
malloc的原型:(void*)malloc(int size)(int也能夠是unsigned,int只是其中的一種特例)
malloc函數的返回值是一個void類型的指針,參數爲int類型數據,即申請分配的內存大小,單位是byte。內存分配成功以後,malloc函數返回這塊內存的首地址。你須要一個指針來接受這個地址。可是因爲函數的返回值是void*類型,因此必須強制轉換成你所接收的類型。也就是說,這塊內存未來要存儲什麼類型的數據。好比:
char* p = (char*)malloc(100);
在堆上面分配了100個字節內存,返回這塊內存的首地址,把地址強制轉換成char*類型後賦給char*類型 的指針變量p。同時告訴咱們這塊內存未來用來存儲char*類型的數據。也就是說你只能經過指針變量p來操做這塊內存。這塊內存自己並無名字,對它的訪問是匿名訪問。
內存釋放
有分配就必定有釋放。malloc對應的就是free函數。free函數只有一個參數,就是要釋放的內存塊的首地址。好比:free(p);
free函數作的事情:斬斷指針變量與這塊內存的關係。就像上面的例子同樣malloc函數開闢的這一個數據塊空間是屬於p的,你只能經過p來訪問這一塊數據塊空間,而free函數作的事情就是斬斷malloc和p之間的聯繫。可是p指針自己存放的地址並無發生變化,只是它對指針所指向的那塊內存已經沒有全部權了,不能對內存塊進行操做。而那塊內存塊裏面的數據也沒有被改變,只是你沒有辦法去訪問或者修改那塊數據快中的內容了。
malloc和free是一一對應的,若是malloc兩次可是隻free一次就會存在內存泄漏,若是malloc一次可是free了兩次,就會出錯(第一次使用free的時候,malloc所開闢的空間就已經被釋放,第二次使用free就無內存空間能夠釋放了,這種對內存的誤操做就有可能會致使程序的崩潰)。
函數的內存釋放完後,必定要把p指針置爲NULL。爲何?
從上面能夠看出,free掉以後p只是切斷了和內存空間的關係,可是p指針自己內部依舊存在一個地址,若是不把它置成空,那這個指針就會變成一個野指針(懸垂指針),早晚會出事。
1 char* p = (char*)malloc(100); 2 strcpy(p, "hello"); 3 free(p);//能夠看到這邊已經釋放了p所指向的那一塊空間,可是p自己存儲的地址並無改變 4 if(NULL != p)//判斷不起做用,起不到防禦做用 5 { 6 strcpy(p, "world");//p沒有分配空間,出錯。 7 }
4、new/delete
前頭講了不少但好像尚未講到c++的動態內存這方面。下面咱們來進行一些討論。
咱們知道c++是兼容c的,那咱們明明已經有了malloc和free來進行動態內容的管理,爲何c++還要定義new和delete運算符來動態管理內存。
來看一下它們之間的區別和聯繫:
1.它們都是動態管理內存的入口。
2.malloc/free是c/c++標準庫的函數,new/delete是c++操做符。
3.malloc/free只是動態分配/釋放內存空間。而new/delete出來分配空間還會調用構造函數和析構函數進行初始化與清理。
4.malloc/free須要手動計算類型大小且會返回void*, new/delete能夠本身計算類型的大小,返回對應類型的指針。
咱們在c++中是容許進行重載的,那咱們也能夠重載一下new和delete,我在這就不作了(其實new和delete是不能重載的,即便你進行了重載,也只是重載了operator new和operator delete)。
有關operator new/operator delete operator new[]/operator delete[]
總結:
1.operator new/operator delete operator new[]/operator delete[]的用法和malloc/free同樣。
2.它們只負責分配空間/釋放空間,不會調用對象構造函數和析構函數來初始化/清理對象。
3.實際operator new/operator delete 只是malloc和free的一層封裝。
5、new和delete在內存中所作的事