61

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

void replaceNumberAndPrint(int array[3]) {
    printf("%i\n", array[1]);
    printf("%i\n", array[1]);
}

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

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

上面这段代码的输出:

65
4202656

我究竟做错了什么?“4202656”是什么意思?

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

4

10 回答 10

61

myArray是一个局部变量,因此指针仅在其范围(在本例中为包含函数getArray)结束之前才有效。如果您稍后访问它,您将获得未定义的行为。

在实践中发生的情况是调用printf覆盖了使用的堆栈部分,myArray然后它包含一些其他数据。

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

我错过的另一种选择(可能甚至是这里最好的一种,只要数组不太大)是将数组包装到结构中,从而使其成为值类型。然后返回它会创建一个在函数返回后仍然存在的副本。有关详细信息,请参阅tp1答案

于 2010-12-31T13:31:25.363 回答
19

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

当您在replaceNumberAndPrint函数中访问数组时,结果是未定义的。它似乎第一次起作用的事实只是一个幸运的巧合。可能您指向的内存位置在堆栈上未分配,并且仍然为第一次调用正确设置,但是调用printf然后通过在其操作期间将值压入堆栈来覆盖它,这就是为什么第二次调用printf显示不同的东西。

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

于 2010-12-31T13:32:00.190 回答
8

尝试类似的东西。myArray如果它是本地定义的,那么你这样做的方式会“杀死”原因。

#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
 printf("%i\n", array[0]);
 printf("%i\n", array[1]);
 printf("%i\n" , 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/

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

#include <stdio.h>
#include <stdlib.h>

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

    printf("%i\n", array[0]);
    printf("%i\n", array[1]);
    printf("%i\n" , 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;
}
于 2010-12-31T13:36:44.717 回答
2

一旦您离开 getArray,myArray 就会超出范围。您需要在堆上为其分配空间。

于 2010-12-31T13:31:59.597 回答
2

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

于 2010-12-31T13:34:10.060 回答
2

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

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

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\n", array[i]);
     destroy_array(array);
     return 0;
 }

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

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\n", array[i]);
     return 0;
 }

如果您不知道是什么static意思,请阅读此问题和答案

于 2010-12-31T14:15:17.297 回答
2

正确的方法如下:

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\n", a.array[i]);
   return 0;
}

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

于 2011-01-02T23:15:14.943 回答
1

C++ 解决方案:

“我可以访问不同函数中的局部变量吗?如果可以,怎么做?”

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

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

例如:

void replaceNumberAndPrint(const std::array<int, 3>& array) {
    printf("%i\n", array[0]);
    printf("%i\n", array[1]);
    printf("%i\n", array[2]);
}

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

在第二个函数中,返回值由编译器优化,因此您无需支付实际复制数组的代价。

于 2016-03-20T11:16:12.330 回答
0

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

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\n",vector[i]);
    }
    getch();
    return 0;
}

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

于 2014-01-07T08:53:51.460 回答
0

..c 中的静态 ..or.. 全局可以解决问题;)

然而,程序将占用这 3 个字节的整个时间,但您避免在这样的简单事情上执行 malloc(建议将 malloc 用于大数组)

另一方面,如果外部函数修改了指针,那么内部的“myArray”将被修改,因为它指向它,就是这样

int myArray[3];
int * getArray() {
    myArray[0] = 4;
    myArray[1] = 65;
    myArray[2] = 23;
    return myArray;
}
于 2020-09-29T02:44:43.940 回答