聲明自動指標變數時,編譯器為其在堆棧區分配記憶體,如果在函數中將另外一個自動變數的地址賦值給自動指標變數,在函數調用完畢後,指向堆棧區的棧頂指標將移動到調用此函數之前的地址位置,從而使自動變數失去意義,返回的失去意義的地址將會使程式不穩定。
函數返回指標。本來就是一個比較容易出問題的操作。在霍頓的《VC++ 入門經典》一書中,給出了一個很有代表性的例子,如下:
// Ex5_11.cpp#include <iostream>using std::cout;using std::endl;double* treble(double); // Function prototypeint main(void){ double num = 5.0; // Test value double* ptr = 0; // Pointer to returned value ptr = treble(num); cout << endl << "Three times num = " << 3.0*num; cout << endl << "Result = " << *ptr; // Display 3*num cout << endl; system("pause"); return 0;}// Function to treble a value - mark 1double* treble(double da ta){ double result = 0.0; result = 3.0*da ta; return &result;}
兩個輸出語句,一個直接輸出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(...);
正確的方法的共同特點是在函數結束前,對返回的指標解除引用。然後用這個數值,為變數或指標指向的記憶體地區賦值。也就是說必須要複製函數的傳回值。因為函數體中變數會被析構。
指標是靈活而強大的,避免低級錯誤,明確基本概念。才能讓指標更好的為我們服務