一定要弄懂GetMemory


堆棧

中分配局部變量空間,是系統自動分配空間。定義一個 char a;系統會自動在棧上為其開辟空間。由於棧上的空間是自動分配自動回收的,所以棧上的數據的生存周期只是在函數的運行過程中,運行后就釋放掉,不可以再訪問。

堆區分配程序員申請的內存空間,堆上的數據只要程序員不釋放空間,就一直可以訪問到,不過缺點是一旦忘記釋放會造成內存泄露。

靜態區是分配靜態變量,全局變量空間的。

[cpp]  view plain  copy
  1. int a = 0; 全局初始化區  
  2. char *p1; 全局未初始化區  
  3. main(){  
  4.      int b;      //棧  
  5.      char s[] = "abc";    //棧  
  6.      char *p2;      //棧  
  7.      char *p3 = "123456";   // 123456\0在常量區,p3在棧上。  
  8.      static int c =0;      //全局(靜態)初始化區  
  9.      p1 = (char *)malloc(10);    //堆  }  
 
        

GetMemory1

[cpp]  view plain  copy
  1. void GetMemory1(char *p)    
  2. {    
  3.     p = (char *)malloc(100);    
  4. }    
  5.     
  6. void Test1(void)    
  7. {    
  8.     char *str = NULL;    
  9.     GetMemory1(str);      
  10.     strcpy(str, "hello world");    
  11.     printf(str);  //str一直是空,程序崩潰     
  12. }    
結果:

分析:

        毛病出在函數GetMemory1 中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是 _p,編譯器使 _p = p。如果函數體內的程序修改了_p的內容,就導致參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。在本例中,_p申請了新的內存,只是把 _p所指的內存地址改變了,但是p絲毫未變。所以函數GetMemory並不能輸出任何東西。事實上,每執行一次GetMemory1就會泄露一塊內存,因為沒有用free釋放內存。Test1中調用GetMemory1時,函數參數為str的副本不是str本身

GetMemory2

[cpp]  view plain  copy
  1. void GetMemory2(char **p, int num)    
  2. {    
  3.     *p = (char *)malloc(num);    
  4. }    
  5.     
  6. void Test2(void)    
  7. {    
  8.     char *str = NULL;    
  9.     GetMemory2(&str, 100);    
  10.     strcpy(str, "hello");      
  11.     printf(str);        
  12. }    

結果:輸出hello

分析:動態分配的內存不會自動釋放;

            沒有測試是否成功分配了內存,應該有if (*p == NULL) { ……} 之類的語句處理內存分配失敗的其情況。

GetMemory3

[cpp]  view plain  copy
  1. char * GetMemory3(void)    
  2. {      
  3.      char p[] = "hello world";    
  4.      return p;    
  5. }    
  6. void Test3(void)    
  7. {    
  8.      char *str = NULL;    
  9.      str = GetMemory3();        
  10.      printf(str);    
  11. }    
結果:輸出亂碼。

分析:字符數組p存在於棧空間,是局部變量,函數返回后,內存空間被釋放,因此輸出無效值。字符數組的值是可以修改的,例如p[0] = 't‘。

GetMemory4

[cpp]  view plain  copy
  1. char *GetMemory4(void)    
  2. {    
  3.     char *p = "hello";    
  4.     return p;    
  5. }    
  6.      
  7. void Test4(void)    
  8. {    
  9.     char *str = NULL;    
  10.     str = GetMemory4();   
  11.     cout<< str << endl;    
  12. }    
結果:輸出hello
分析:p指向的是字符串常量,字符串常量保存在只讀的數據段,是全局區域,但不是像全局變量那樣保存在普通數據段(靜態存儲區)。無法對p所指的內存的內容修改,例如p[0] = 'y;這樣的修改是錯誤的。


GetMemory5

[cpp]  view plain  copy
  1. char *GetMemory5(void)    
  2. {     
  3.      return "hello";    
  4. }    
  5. void Test3(void)    
  6. {    
  7.     char *str = NULL;    
  8.     str = GetMemory5();     
  9.     printf(str);    
  10. }    

結果:輸出hello
分析:直接返回常量區。

GetMemory6

[cpp]  view plain  copy
  1. void GetMemory6(void) {  
  2.     char *str = (char*)malloc(100);  
  3.     strcpy(str, "hello");  
  4.     free(str);  
  5.         //str = NULL,加上這句程序才不會有野指針  
  6.         if (str != NULL) {  
  7.         strcpy(str, "world");  
  8.         printf(str);  
  9.     }  
  10. }  
  11.   
  12. void main(){    
  13.     GetMemory6();  
  14. }    
結果:能夠輸出world,但程序存在問題。

分析:程序出現了野指針

     野指針只會出現在像C和C++這種沒有自動內存垃圾回收功能的高級語言中, 所以java或c#肯定不會有野指針的概念. 當我們用malloc為一個指針分配一個空間后, 用完這個指針,把它free掉,但是沒有讓這個指針指向NULL或某一個特定的空間。如上面程序一樣,將str進行free后,只是釋放了指針所指的內存,但指針並沒有釋放掉,此時指針所指的是垃圾內存;這樣的話,if語句永為真,if判斷無效。delete也存在同樣的問題。

      防止產生野指針:(1)指針變量一定要初始化為NULL,因為任何指針變量剛被創建時不會自動成為NULL指針,它的缺省值是隨機的。(2)當free或delete后,將指針指向NULL。通常判斷一個指針是否合法,都是使用if語句測試該指針是否為NULL。

原文:http://blog.csdn.net/u013074465/article/details/42784267


免責聲明!

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



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