1. 程式人生 > 實用技巧 >C++中如何在函式中返回區域性變數的指標/引用/地址?

C++中如何在函式中返回區域性變數的指標/引用/地址?

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

完成修改,對於指標這類資料,也是一樣的。