C++中如何在函式中返回區域性變數的指標/引用/地址?
阿新 • • 發佈:2020-07-21
01 不能直接返回區域性變數的引用/地址
C++有時候還挺傻的,比如呼叫函式的時候,我就想返回一個區域性變數的引用或指標(常想用於返回新建的陣列/物件),是不正確的。
比如下面這段程式碼,用指標儲存變數 \(a\) 的地址並返回(直接返回 \(a\) 的地址的話,在編譯器那關就過不了):
// 程式 #include <iostream> using namespace std; int *get10(){ int a = 10; int *b = &a; return b; } int main() { int *c10 = get10(); cout << *c10 << endl; return 0; }
// 結果
10
結果似乎是正確的,但是如果我們增加一個函式,真個程式碼是這樣的:
// 程式 #include <iostream> using namespace std; int *get10(){ int a = 10; int *b = &a; return b; } int *get20(){ int a = 20; int *b = &a; return b; } int main() { int *c10 = get10(); int *c20 = get20(); cout << *c10 << endl; cout << *c20 << endl; return 0; }
// 結果
20
22024
可以看出,這個結果是隨機的,我們不能返回區域性變數的指標/引用,這些區域性變數包括:
- 指標
- 引用
- 陣列
- 類物件
- 函式
- …
這些物件的底層儲存都是利用指標來實現的,比如說陣列,在計算機中實際是用指標儲存的是陣列第一個元素的地址。
之所以不能返回區域性變數的指標/引用/地址的原因如下:
區域性變數:在函式內部定義的變數稱為區域性變數,區域性變數儲存在函式棧區,當程式呼叫結束後,在函式棧區的所有東西將會由計算機進行銷燬。
全域性變數:函式外面的變數稱為全域性變數,它隨著程式執行的結束自動進行銷燬。
我們在函式內宣告的區域性變數,想要返回,返回值分為兩種情況:
- 針對
int、float
- 針對涉及到指標這類更為複雜的物件,不做任何處理;
就好像拆遷,兩種情況:
- 你家小的,得了,重新安置一個地方給你。
- 你家大幾千畝,也沒那麼多地方安置你,給你小的你也住不下,那就不賠了,但拆還是要拆的。
所以,我們不應該返回區域性變數的指標或者引用。而第一個程式能得到正確結果原因在於,C++的記憶體清理機制是惰性的,要等到下一位住客住進來,它才會進行記憶體的清理,因而在程式中,我們可以得到10的結果。
02 如何返回複雜的區域性變數
這裡說的複雜,是指用到指標的,主要有三種處理方法:
- 函式內new出來,函式外用完delete(反人類,不安全);
- static 改為靜態的(隨著整個程式結束才銷燬,浪費空間)
- 作為全域性變數,將地址傳入函式(推薦)
這裡只說第三種方法(Python之禪,對於某個效果,有且只有一個實現):
- 函式外定義全域性變數
- 將變數引用傳入函式
- 函式內完成修改
// 程式
#include <iostream>
using namespace std;
void add_x_to_Array(int array[], int x, int n){
for (int i = 0; i < n; ++i) {
array[i] = array[i] + x;
}
}
int main() {
int array[2] = {0, 1};
add_x_to_Array(array, 10, 2);
for (int i = 0; i < 2; ++i) {
cout << array[i] << endl;
}
return 0;
}
10
11
完成修改,對於指標這類資料,也是一樣的。