函式不能返回區域性指標變數

pamxy發表於2013-07-26

轉自:http://blog.csdn.net/snakewarhead/article/details/8046673

宣告自動指標變數時,編譯器為其在堆疊區分配記憶體,如果在函式中將另外一個自動變數的地址賦值給自動指標變數,在函式呼叫完畢後,指向堆疊區的棧頂指標將移動到呼叫此函式之前的地址位置,從而使自動變數失去意義,返回的失去意義的地址將會使程式不穩定。


函式返回指標。本來就是一個比較容易出問題的操作。在霍頓的《VC++ 入門經典》一書中,給出了一個很有代表性的例子,如下:

  1. // Ex5_11.cpp  
  2.   
  3. #include <iostream>  
  4.   
  5. using std::cout;  
  6.   
  7. using std::endl;  
  8.   
  9. double* treble(double);                   // Function prototype  
  10.   
  11. int main(void)  
  12.   
  13. {  
  14.   
  15.    double num = 5.0;                      // Test value  
  16.   
  17.    double* ptr = 0;                       // Pointer to returned value  
  18.   
  19.    ptr = treble(num);  
  20.   
  21.    cout << endl  
  22.   
  23.         << "Three times num = " << 3.0*num;  
  24.   
  25.    cout << endl  
  26.   
  27.         << "Result = " << *ptr;           // Display 3*num  
  28.   
  29.    cout << endl;  
  30.   
  31.    system("pause");  
  32.   
  33.    return 0;  
  34.   
  35. }  
  36.   
  37. // Function to treble a value - mark 1  
  38.   
  39. double* treble(double da  
  40.    
  41. ta)  
  42.   
  43. {  
  44.   
  45.    double result = 0.0;  
  46.   
  47.    result = 3.0*da  
  48.    
  49. ta;  
  50.   
  51.    return &result;  
  52.   
  53. }  



兩個輸出語句,一個直接輸出3*5=15.另一個在一個函式中進行了乘法運算,也是5*3,存到result變數中也沒有任何問題。返回這個變數的指標,輸出時再接觸引用。貌似也沒有錯誤。兩條輸出語句似乎都應該輸出15.但事實不是這樣。編譯器會丟擲[Warning] address of local variable `result' returned 這樣一個警告資訊。程式執行後的結果也並非是我們預想的那樣。第二條輸出語句會輸出一個不可預見的值。這是怎麼回事呢?

仔細分析一下,result是作用域在treble函式中的區域性變數。當函式執行結束後。變數result會被析構。其原先佔用的記憶體區域已經被系統回收,可以儲存任何資料。而返回的指向該地址的指標也失去了其原有的意義。因此我們得到這樣一條準則:

永遠不要從函式中返回區域性自動變數的地址。

 

如果你真的需要這樣操作。你可以在函式的參數列中傳入一個指標變數。然後將需要寫入的資料寫入到該指標變數指向的地址。由於該指標指向的變數,作用域在函式體之外。因此不會在函式結束結束時被回收。

現在回到我們遇到的問題。時間函式localtime就是一個返回指標的函式。返回值型別:tm*

該如何接收這個返回值?當然是宣告一個與之型別相同的變數。

於是你會這樣寫:tm* result;

接下來呢?還用問?賦值嘛。是不是這樣:result=localtime(....);

返回什麼型別,當然要給什麼型別的變數賦值。但是這樣卻發生了我們不想看到的結果。

也許你想到了。就是這個指標!返回的指標在函式結束後不再有效。正確的方法可以是:

tm result;

result = *localtime(....);

也可以是:

tm* result;

*result = *localtime(...);

正確的方法的共同特點是在函式結束前,對返回的指標解除引用。然後用這個數值,為變數或指標指向的記憶體區域賦值。也就是說必須要複製函式的返回值。因為函式體中變數會被析構。

指標是靈活而強大的,避免低階錯誤,明確基本概念。才能讓指標更好的為我們服務


相關文章