C - 避免警告“与返回的局部变量关联的堆栈内存的地址”

J. *_*dge 2 c arrays pointers

我编写了以下简单的程序,对 0 到 9 的数字进行求和:

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

int* allocArray() {
    int arr[10];
    return arr;
}

int main(void){
    int* p;
    int summe = 0;
    p = allocArray();
    for(int i = 0; i != 10; ++i) {
        p[i] = i;
    }
    for(int i = 0; i != 10; ++i) {
        summe += p[i];
    }
    printf("Sum = %d\n", summe);
}
Run Code Online (Sandbox Code Playgroud)

该代码编译并提供预期结果“45”。但是我收到以下警告:“返回与局部变量‘arr’关联的堆栈内存地址”。我究竟做错了什么?

tad*_*man 5

这是未定义的行为,简单明了。它“起作用”的唯一原因是因为对于这个特定的编译器,堆栈还没有被丢弃,但它是靠借来的时间生存的。

函数调用完成后,其生命周期arr立即结束。在那之后,任何指向的指针都arr将失效并且无法使用。1

您的编译器使用堆栈内存来存储局部变量,并且警告表明您正在将地址返回到现已无效的堆栈变量。

解决这个问题的唯一方法是动态分配内存并返回:

int* allocArray() {
    int* arr = calloc(10, sizeof(int));

    return arr;
}
Run Code Online (Sandbox Code Playgroud)

您现在负责稍后释放该内存。

您还可以使用以下方法static来延长使用寿命arr

int* allocArray() {
    static int arr[10];

    return arr;
}
Run Code Online (Sandbox Code Playgroud)

尽管这也不是没有后果,因为现在arr是共享的,而不是每个函数调用所独有的。


1就像 C 中的许多事情一样,您“不能做”的事情(因为它们会导致未定义的行为和/或崩溃)与您“可以做”的事情(因为语法和编译器允许)之间存在显着重叠。通常您有责任了解您编写的任何代码(无论是暗示的还是其他方式)的后果。