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++內存管理還有很多內容,需要進一步加強學習。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM