函數返回指針。本來就是一個比較容易出問題的操作。在霍頓的《VC++ 入門經典》一書中,給出了一個很有代表性的例子,如下:
// Ex5_11.cpp
#include <iostream>
using std::cout;
using std::endl;
double* treble(double); // Function prototype
int 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 1
double* treble(double data)
{
double result = 0.0;
result = 3.0*data;
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(...);
正確的方法的共同特點是在函數結束前,對返回的指針解除引用。然後用這個數值,為變量或指針指向的內存區域賦值。也就是說必須要復制函 數的返回值。因為函數體中變量會被析構。
指針是靈活而強大的,避免低級錯誤,明確基本概念。才能讓指針更好的為我們服務。
*