关于c ++:如何使用指针从不同的函数访问局部变量?

How to access a local variable from a different function using pointers?

我可以访问不同函数中的局部变量吗?如果是这样,怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void replaceNumberAndPrint(int array[3]) {
    printf("%i
"
, array[1]);
    printf("%i
"
, array[1]);
}

int * getArray() {
    int myArray[3] = {4, 65, 23};
    return myArray;
}

int main() {
    replaceNumberAndPrint(getArray());
}

上述代码的输出:

1
2
65
4202656

我做错什么了?"4202656"是什么意思?

我是否必须复制replaceNumberAndPrint()函数中的整个数组才能比第一次访问更多?


myArray是一个局部变量,因此指针只有在其作用域(在本例中是包含函数getArray的作用域)结束时才有效。如果您稍后访问它,将得到未定义的行为。

实际上,对printf的调用会覆盖myArray所使用的堆栈部分,然后包含一些其他数据。

要修复代码,您需要在足够长的作用域(示例中的main函数)中声明数组,或者在堆中分配数组。如果你在堆上分配它,你需要手动释放它,或者在C++中使用RAII。

我遗漏的一个选择(可能是这里最好的一个,前提是数组不太大)是将数组包装成一个结构,从而使它成为一个值类型。然后返回它会创建一个在函数返回之后仍然存在的副本。有关详细信息,请参阅TP1的答案。


一旦超出范围,就不能访问局部变量。这就是局部变量的含义。

在replacenumberandprint函数中访问数组时,结果未定义。这似乎是第一次奏效,这只是一个幸运的巧合。可能您指向的内存位置在堆栈上未分配,并且仍然为第一个调用正确设置,但对printf的调用随后会通过在堆栈操作期间将值推送到堆栈来覆盖此位置,这就是第二个对printf的调用显示不同的内容的原因。

您需要将数组数据存储在堆中并传递一个指针,或者保存在作用域中的变量中(例如全局变量或主函数中作用域的某个变量)。


尝试类似的方法。你这样做会"杀死"myArray,如果它是本地定义的话。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
 printf("%i
"
, array[0]);
 printf("%i
"
, array[1]);
 printf("%i
"
, array[2]);
 free(array);
}

int * getArray() {
 int * myArray = malloc(sizeof(int) * 3);
 myArray[0] = 4;
 myArray[1] = 64;
 myArray[2] = 23;
 //{4, 65, 23};
 return myArray;
}

int main() {
 replaceNumberAndPrint(getArray());
}

更多:http://www.cplusplus.com/reference/clibrary/cstdlib/malloc/

编辑:正如评论正确指出的那样:更好的方法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
    if(!array)
        return;

    printf("%i
"
, array[0]);
    printf("%i
"
, array[1]);
    printf("%i
"
, array[2]);
}

int * createArray() {
    int * myArray = malloc(sizeof(int) * 3);

    if(!myArray)
        return 0;

    myArray[0] = 4;
    myArray[1] = 64;
    myArray[2] = 23;
    return myArray;
}

int main() {
    int * array = createArray();
    if(array)
    {
        replaceNumberAndPrint(array);
        free(array);
    }
    return 0;
}


正确的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Arr {
   int array[3];
};
Arr get_array() {
   Arr a;
   a.array[0] = 4;
   a.array[1] = 65;
   a.array[2] = 23;
   return a;
}
int main(int argc, char **argv) {
   Arr a = get_array();
   for(size_t i=0; i<3; i++)
       printf("%d
"
, a.array[i]);
   return 0;
}

要理解为什么需要这样做,您需要知道sizeof(array)是如何工作的。C(因此C++)努力避免复制数组,而你需要Strut通过它。为什么需要复制是因为作用域——get_array()函数的作用域消失了,该作用域中仍然需要的每个值都需要复制到调用作用域。


局部变量在返回时超出范围,因此不能返回指向局部变量的指针。

您需要使用mallocnew动态地(在堆上)分配它。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int *create_array(void) {
    int *array = malloc(3 * sizeof(int));
    assert(array != NULL);
    array[0] = 4;
    array[1] = 65;
    array[2] = 23;
    return array;
 }
 void destroy_array(int *array) {
     free(array);
 }
 int main(int argc, char **argv) {
     int *array = create_array();
     for (size_t i = 0; i < 3; ++i)
         printf("%d
"
, array[i]);
     destroy_array(array);
     return 0;
 }

或者,您可以将数组声明为静态的,记住语义是不同的。例子:

1
2
3
4
5
6
7
8
9
10
11
int *get_array(void) {
    static int array[] = { 4, 65, 23 };
    return array;
 }
 int main(int argc, char **argv) {
     int *array = get_array();
     for (size_t i = 0; i < 3; ++i)
         printf("%d
"
, array[i]);
     return 0;
 }

如果您不知道static的意思,请阅读此问题和答案。


您的代码调用未定义的行为,因为myArraygetArray()返回时超出范围,并且任何使用(取消引用)悬空指针的尝试都是ub。


离开GetArray后,MyArray就超出范围。您需要在堆上为它分配空间。


C++解决方案:

"May I have any access to a local variable in a different function? If so, how?"

答案是"否",而不是在函数结束后。此时局部变量被销毁。

C++中,处理返回数组的方法是在一个容器中管理它们,如std::array(固定大小)或std::vector(动态大小)。

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
void replaceNumberAndPrint(const std::array<int, 3>& array) {
    printf("%i
"
, array[0]);
    printf("%i
"
, array[1]);
    printf("%i
"
, array[2]);
}

std::array<int, 3> getArray() {
    std::array<int, 3> myArray = {4, 65, 23};
    return myArray;
}

在第二个函数中,编译器对返回值进行了优化,因此您不必为实际复制数组付出代价。


在这段代码中,您使用了指向局部对象的指针,但是当函数返回时,所有局部变量都超出范围。如果要分配内存(使用malloc()函数进行分配),则不会丢失或覆盖任何数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int* getArray(int size) {
    int *myArray = (int*)malloc(size*sizeof(int));
    myArray[0] = 4;
    myArray[1] = 65;
    myArray[2] = 23;
    return myArray;
}

int main() {
    int i;
    int *vector = getArray(3);
    for(i=0;i<3;i++)
    {
        printf("%i
"
,vector[i]);
    }
    getch();
    return 0;
}

此代码将打印所有数组元素,不会发生覆盖。