調用某個函數時經常需要函數返回一個值,我們都知道c++ 的函數返回的是一個copy,所以當只返回一個值時不會出現什么問題,直接return一個copy就行了,但是如果返回一個數組,事情就變得有趣了,我最近就遇到了這個問題。
先附上代碼吧:
#include<iostream> using namespace std; //函數聲明 int * fun1(); int * fun2(); int * fun3(int * const buf); //buf 實際上是個傳出參數,const表示buf的指向不能更改 void dispArr(int *arr ,int n); const int arrlen = 10; int main() { //方法一,返回局部變量的首地址 int * arr; arr = fun1(); cout << "這是方法一" << endl; //dispArr(arr, arrlen); //運行會報錯 /*方法二,在函數內部通過new動態創建數組, 然后記得在main函數使用完數組后將其delete下*/ cout << "這是方法二" << endl; int *arr1; arr1 = fun2(); dispArr(arr1, arrlen); delete arr1; //方法三,由調用者自己申請緩存區和釋放緩存區 cout << "這是方法三" << endl; int *arr2 = new int[arrlen]; int *ret = fun3(arr2); dispArr(arr2, arrlen); delete arr2; return 0; } //函數定義 int *fun1() { int temp[arrlen]; for (int i = 0; i < arrlen;++i) { temp[i] = i; } return temp; } int *fun2() { int *temp = new int[arrlen]; for (int i = 0; i < arrlen; i++) { temp[i] = i; } return temp; } int *fun3(int* const buf) { if(buf==NULL) { cerr<<"error: null ptr @buf"<<endl; return NULL; } for(int i=0; i<arrlen; i++) { buf[i]=i; } return buf; } void dispArr(int* arr, int n) { for (int i = 0; i < n; i++) { cout << "arr" << "[" << i << "]" << " is:" <<arr[i]<<endl; } }
這是運行結果 :
這是方法一 Segmentation fault (core dumped) 這是方法二 arr[0] is:0 arr[1] is:1 arr[2] is:2 arr[3] is:3 arr[4] is:4 arr[5] is:5 arr[6] is:6 arr[7] is:7 arr[8] is:8 arr[9] is:9 這是方法三 arr[0] is:0 arr[1] is:1 arr[2] is:2 arr[3] is:3 arr[4] is:4 arr[5] is:5 arr[6] is:6 arr[7] is:7 arr[8] is:8 arr[9] is:9
通過一個函數創建一個數組,然后將數組的首地址返回,在主函數里將數組里的內容輸出。拿到這個問題,像我這樣初學者首先建立的思路是,你不是要我返回一個數組嗎,我就返回一個數組的首地址給你啊,然后你根據這個地址去尋址,不就可以了嗎。一開始我也這么想,因為我在java里就是這么干,所以很自然就想到了,然而是錯的,而且是范了很傻的錯誤,因為在函數里創建的變量存儲在棧里,函數返回將被自動釋放,再返回一個地址,這個地址就指向了一個非法區域,程序報錯。所以正確的方法是使用new的方式來申請一段位於堆區的內存,指針指向這段內存,函數返回時內存不會被釋放掉;但需要注意使用完畢后delete相應的區域,養成良好的習慣。fun2的方法不好,因為調用者可能會不知道要delete,所以一般情況下是告訴調用者傳入一個緩沖區的首地址給函數,函數返回該首地址,內存的申請和釋放由調用者來做,如fun3。當然,一切都是浮雲,STL才是王道。
總結一下
千萬不要返回一個局部變量的指針或引用,會運行錯誤。 即使不錯誤,得到的指針所指內容在函數結束后就已經變了。
關於c++函數返回值和參數調用想了解更多,可以點 這里 。