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

完成修改,对于指针这类数据,也是一样的。

posted @ 2020-07-21 22:01  疯狂的荷兰人  阅读(7758)  评论(0编辑  收藏  举报