C++ 陣列在記憶體中的分配
接前一篇的內容,C++中陣列在記憶體中也有靜態分配和動態分配的區別。靜態陣列建立的方式為:A a[],它在棧上分配空間;動態方式是使用new,malloc在堆上分配。
陣列要麼在靜態儲存區被建立(如全域性陣列),要麼在棧或堆上被建立。陣列名對應著(而不是指向)一塊記憶體,其地址與容量在生命期內保持不變,只有陣列的內容可以改變。看下例:
1 #include<iostream> 2 using namespace std; 3 void test() 4 { 5 char ch[]="hello"; 6 ch[0]='H'; 7 char*p="world"; 8 p[0]='W';//出錯 9 cout<<ch<<endl; 10 cout<<p<<endl; 11 } 12 int main() 13 { 14 test(); 15 return 0; 16 }
程式中用指標指向了一個常量字串"world",C++常量字串存在常量儲存區,且不能修改,故會出錯。
陣列的在棧上分配,或堆上分配的區別可以看下例:將test和main函式修改為下
1 char* test() 2 { 3 char ch[]="hello";//在棧上 4 /* char* ch= new char[6];//在堆上 5 ch[0]='h'; 6 ch[1]='e'; 7 ch[2]='l'; 8 ch[3]='l'; 9 ch[4]='0'; 10 ch[5]='\0'; 11 */ 12 return ch; 13 } 14 int main() 15 { 16 char*p=test(); 17 cout<<p<<endl; 18 return 0; 19 }
很明顯程式程式編譯時出現:warning C4172: returning address of local variable or temporary。在test呼叫結束後在棧上分配的陣列已經銷燬,p即為野指標指向無效內容。這裡把陣列名作為l函式返回值。如果換成下面註釋的程式碼在堆上分配則沒有問題,注意最後的'\0',字串的最後是以'\0'來判斷結束的,不然會出界輸出無效內容。這裡可以看出C++陣列在記憶體中的儲存形式與上篇內容介紹的一樣。將test改為如下:
1 char* test() 2 { 3 char* ch= new char[6];//在堆上 4 ch[0]='h'; 5 ch[1]='e'; 6 ch[2]='l'; 7 ch[3]='l'; 8 ch[4]='0'; 9 ch[5]='\0'; 10 char c[] = "hello world"; 11 char *p = c; 12 cout<< sizeof(c) << endl; // 12位元組 13 cout<< sizeof(ch) << endl; // 4位元組 14 cout<< sizeof(p) << endl; // 4位元組 15 return ch; 16 }
靜態陣列名用sizeof可以知道陣列實際所佔的記憶體大小,而指向陣列的指標佔用空間即為普通指標的大小。當陣列作為函式的引數進行傳遞時,該陣列自動退化為同類型的指標。
在上一篇關於C++中類在記憶體中分配的介紹舉例時發現一個問題,當兩個指標指向同一個物件時,發現delete一個指標銷燬該物件後,用另一個指標扔能呼叫該類的函式,這個是野指標應該有錯啊。看下面的例子:
1 #include<iostream> 2 using namespace std; 3 class A 4 { 5 public: 6 void fun() 7 { 8 cout<<"class of a:"<<endl; 9 } 10 int num; 11 }; 12 A* test() 13 { 14 A*p; 15 A a; 16 a.num=11; 17 p=&a; 18 p->fun(); 19 return p; 20 } 21 int main() 22 { 23 A*s=test(); 24 s->fun(); 25 return 0; 26 }
程式執行結果:
即兩次輸出class of a,一次是在test函式內,一次是s呼叫。test內的a分配在棧上,函式結束後應該就銷燬了,為什麼s還能呼叫fun。原來類中的成員資料和函式是存放在不同位置的。C++類的方法存放在"程式程式碼區",而類中的資料成員(物件資料成員)存放在類的例項物件中,即該成員資料存放在堆或棧中。s指向物件的成員資料已銷燬,而類的方法還在。
若將上面程式碼第8行改為:cout<<"class of a:"<<this->num<<endl;程式執行結果為:
即s輸出的資料成員num為無效,因為該物件已釋放。關於C++記憶體管理還有很多內容,需要進一步加強學習。