一、內存分配分類
1.從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static 變量。
2.在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。
3.從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多。
二、傳遞動態內存
1.動態指針傳遞失敗
1 #include<iostream> 2 using namespace std; 3 void GetMe(char *p,int num) 4 { 5 p=(char*)malloc(sizeof(char)*num); 6 } 7 int main() 8 { 9 char *str=NULL; 10 GetMe(str,100); 11 strcpy(str,"Hello!"); 12 cout<<str<<endl; 13 return 0; 14 }
?
結果:程序運行奔潰,因為str還是為NULL,往空的地址強行賦值時,內存出錯
原因:str并沒有獲取指針p開辟的空間。本質為調用函數 GetMe 時,函數會初始化函數內的局部變量,同時為傳進來的實參str(指針和值都創建,引用除外)創建一個副本 _p,? _num,所以 p申請了內存,只是把p指向的內存地址改變,而str并沒有改變,所以str依然沒有獲得內存。同時每次p申請的內存都不會得到釋放,最終會造成內存泄露。
2.正確的傳遞動態內存
2.1? 返回指針
1 #include<iostream> 2 using namespace std; 3 char* GetMe(char *p,int num) 4 { 5 p=(char*)malloc(sizeof(char)*num); 6 return p; 7 } 8 int main() 9 { 10 char *str=NULL; 11 str=GetMe(str,100); 12 strcpy(str,"Hello!"); 13 cout<<str<<endl; 14 delete str; 15 return 0; 16 }
結果:正常運行
原因:p申請了空間,并將該空間的地址作為返回值傳給str,這樣str就指向了p申請的內存空間
2.2?傳遞指針
1 #include<iostream> 2 using namespace std; 3 void GetMe(char **p,int num) 4 { 5 *p=(char*)malloc(sizeof(char)*num); 6 } 7 int main() 8 { 9 char *str=NULL; 10 GetMe(&str,100); 11 strcpy(str,"Hello!"); 12 cout<<str<<endl; 13 delete str; 14 return 0; 15 }
結果:正常運行
原因:傳遞了str的指針給函數GetMe(),那么p就是str的地址的副本,地址的副本指向的內存是固定,所以該函數是為str地址指向的str開辟空間
?3.引用傳遞
1 #include<iostream> 2 using namespace std; 3 void GetMe(char* &p,int num) 4 { 5 p=(char*)malloc(sizeof(char)*num); 6 } 7 int main() 8 { 9 char *str=NULL; 10 GetMe(str,100); 11 strcpy(str,"Hello!"); 12 cout<<str<<endl; 13 return 0; 14 }
結果:正常運行
原因:引用就是原傳遞實參的別名,地址相同,指向相同的地址空間
?
總結:實際上指針傳遞仍然是一種值傳遞,只不過在參數是指針的時候,傳遞的是指針的副本,這樣在地址上的操作實際就反映到了內存中。
?
?