01 不能直接返回局部變數的引用/地址 C++有時候還挺傻的,比如調用函數的時候,我就想返回一個局部變數的引用或指針(常想用於返回新建的數組/對象),是不正確的。 比如下麵這段代碼,用指針存儲變數 \(a\) 的地址並返回(直接返回 \(a\) 的地址的話,在編譯器那關就過不了): // 程式 #i ...
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
完成修改,對於指針這類數據,也是一樣的。