使用關鍵字NEW分配內存 在講解分配內存之前,首先來理解下內存區劃分、內存分配、常量存儲區、堆、棧、自由存儲區、全局區這些也是初學者容易混淆的地方。我的博客中有一篇文章描述C語言中代碼分配情況,點擊鏈接 下面部分是轉載於:http://blog.sina.com.cn/s/blog_7edcf63b0100yhk9.html 一. 在c中分為這幾個存儲區 1.棧 ——由編譯器自動分配釋放 2.堆 ——一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收 3.全局區(靜態區)——全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域(C++中已經不再這樣劃分)。- 程序結束釋放 4.另外還有一個專門放常量的地方。- 程序結束釋放 在 (a)函數體中定義的變量通常是在棧上, (b)用malloc, calloc, realloc等分配內存的函數分配得到的就是在堆上。 (c)在所有函數體外定義的是全局量, (d)加了static修飾符後不管在哪裡都存放在全局區(靜態區), (e)在所有函數體外定義的static變量表示在該文件中有效,不能extern到別的文件用, (f)在函數體內定義的static表示只在該函數體內有效。 (7)另外,函數中的"adgfdf"這樣的字符串存放在常量區。 [cpp] int a = 0; //全局初始化區 char *p1; //全局未初始化區 void main() { int b; //棧 char s[] = "abc"; //棧 char *p2; //棧 char *p3 = "123456"; //123456{post.content}在常量區,p3在棧上 static int c = 0; //全局(靜態)初始化區 p1 = (char *)malloc(10); //分配得來得10字節的區域在堆區 p2 = (char *)malloc(20); //分配得來得20字節的區域在堆區 strcpy(p1, "123456"); //123456{post.content}放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一塊 } 二.在C++中,內存分成5個區,他們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區 1.棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變量的存儲區。裡面的變量通常是局部變量、函數參數等。 2.堆,就是那些由new分配的內存塊,他們的釋放編譯器不去管,由我們的應用程序去控制,一般一個new就要對應一個delete。如果程序員沒有釋放掉,那麼在程序結束後,操作系統會自動回收。 3.自由存儲區,就是那些由malloc等分配的內存塊,他和堆是十分相似的,不過它是用free來結束自己的生命的。 4.全局/靜態存儲區,全局變量和靜態變量被分配到同一塊內存中,在以前的C語言中,全局變量又分為初始化的和未初始化的,在C++裡面沒有這個區分了,他們共同占用同一塊內存區。 5.常量存儲區,這是一塊比較特殊的存儲區,他們裡面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改) 明確區分堆與棧: 在bbs上,堆與棧的區分問題,似乎是一個永恆的話題,由此可見,初學者對此往往是混淆不清的,所以我決定拿他第一個開刀。 首先,我們舉一個例子: [cpp] 1 void f() 2 { 3 int* p=new int[5]; 4 } 這條短短的一句話就包含了堆與棧,看到new,我們首先就應該想到,我們分配了一塊堆內存,那麼指針p呢?他分配的是一塊棧內存,所以這句話的意思就是:在棧內存中存放了一個指向一塊堆內存的指針p。在程序會先確定在堆中分配內存的大小,然後調用operator new分配內存,然後返回這塊內存的首地址,放入棧中,他在VC6下的匯編代碼如下: 00401028 push 14h 0040102A call operator new (00401060) 0040102F add esp,4 00401032 mov dword ptr [ebp-8],eax 00401035 mov eax,dword ptr [ebp-8] 00401038 mov dword ptr [ebp-4],eax 這裡,我們為了簡單並沒有釋放內存,那麼該怎麼去釋放呢?是delete p麼?澳,錯了,應該是delete []p,這是為了告訴編譯器:我刪除的是一個數組,VC6就會根據相應的Cookie信息去進行釋放內存的工作。 好了,我們回到我們的主題:堆和棧究竟有什麼區別? 主要的區別由以下幾點: 1、管理方式不同; 2、空間大小不同; 3、能否產生碎片不同; 4、生長方向不同; 5、分配方式不同; 6、分配效率不同; 以下是摘與另外一篇博客C++中new和malloc的區別 . 一:new delete 是運算符,malloc,free是函數 malloc與free是C++/C語言的標准庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。 對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。 因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。 我們先看一看malloc/free和new/delete如何實現對象的動態內存管理,見示例。 [cpp] class Obj { public : Obj(void){ cout << “Initialization” << endl; } ~Obj(void){ cout << “Destroy” << endl; } void Initialize(void){ cout << “Initialization” << endl; } void Destroy(void){ cout << “Destroy” << endl; } }; void UseMallocFree(void) { Obj *a = (obj *)malloc(sizeof(obj)); // 申請動態內存 a->Initialize(); // 初始化 //… a->Destroy(); // 清除工作 free(a); // 釋放內存 } void UseNewDelete(void) { Obj *a = new Obj; // 申請動態內存並且初始化 //… delete a; // 清除並且釋放內存 } 示例用malloc/free和new/delete如何實現對象的動態內存管理 類Obj的函數Initialize模擬了構造函數的功能,函數Destroy模擬了析構函數的功能。函數UseMallocFree中,由於malloc/free不能執行構造函數與析構函數,必須調用成員函數Initialize和Destroy來完成初始化與清除工作。函數UseNewDelete則簡單得多。 所以我們不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由於內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。 既然new/delete的功能完全覆蓋了malloc/free,為什麼C++不把malloc/free淘汰出局呢?這是因為C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。 如果用free釋放“new創建的動態對象”,那麼該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內存”,理論上講程序不會出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。 二:new delete在實現上其實調用了malloc,free函數。 三:new operator除了分配內存,還要調用構造函數。 malloc函數只是負責分配內存。 ×××××××××××××××××××××××××××××××××××以上是轉載部分×××××××××××××××××××××××××× [cpp] #include <iostream> /*C++ 內存分配、使用和刪除指針*/ using namespace std; int main() { int localVariable = 5; int *pLocal = &localVariable; /*申請空間*/ int *pHeap = new int; *pHeap = 7; cout << "localVariable:" << localVariable << endl; cout << "*pLocal:" << *pLocal << endl; cout << "*pHeap:" << *pHeap << endl; /*釋放空間*/ delete pHeap; pHeap = new int; *pHeap = 9; cout << "pHeap: " << *pHeap << endl; delete pHeap; return 0; } 輸出 [cpp] localVariable:5 *pLocal:5 *pHeap:7 pHeap: 9 程序中每個new 都應該有對應delete ,否則會造成內存洩露。 [cpp] //using new and delete #include <iostream> using namespace std; class Simplecat{ public: Simplecat(); ~Simplecat(); private: int itsAge; }; Simplecat::Simplecat() { cout << "Constructor called ******" << endl; itsAge = 1; } Simplecat::~Simplecat() { cout << "Destructor called." << endl; } int main() { cout << "Simplecat Frisky******start *****"<< endl; Simplecat Frisky; cout << "Simplecat Frisky******end******"<< endl; cout <<"new Simplecat*******start******"<< endl; Simplecat *ptags = new Simplecat; delete ptags; cout << "new Simplecat******end******"<<endl; return 0; } [cpp] Simplecat Frisky******start ***** Constructor called ****** Simplecat Frisky******end****** new Simplecat*******start****** Constructor called ****** Destructor called. new Simplecat******end****** Destructor called. [cpp]