在其内存应该已被释放后访问可变长度数组

Posted

技术标签:

【中文标题】在其内存应该已被释放后访问可变长度数组【英文标题】:accessing variable length array after its memory should have been deallocated 【发布时间】:2018-11-17 01:30:37 【问题描述】:

我目前正在研究可变长度数组和自动存储。

我有以下代码为函数vla 内部的可变长度数组myArray 分配内存,并从函数返回指向可变长度数组的指针。

#include <stdio.h>

int * vla(int n)
    int myArray[n];

    myArray[0] = 10;
    myArray[1] = 11;

    int * pointerToInt = myArray;
    return pointerToInt;


int main(void)

    int * pointerToInt = vla(10);

    printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 10, 11

    return 0;

我以为变长数组属于自动存储类(即当我们进入包含变长数组的函数时会为变长数组分配内存,函数退出后会自动释放内存)

那么按照这个逻辑,分配给myArray变长数组的内存在我们从vla方法返回后就被释放了,但是为什么我仍然可以正确访问变长数组的第一个和第二个元素呢?

这种行为是否已定义?还是只是碰巧起作用的未定义行为?

【问题讨论】:

这是未定义的行为,就像myArray 是一个普通的固定大小数组 是的,未定义的行为发生了。 myArray 是在堆栈内存上创建的堆栈/自动变量。记住记忆永远存在。它只是由基于分配和释放的不同指针拥有。您仍然可以访问相同值的原因是同一块内存没有分配给另一个指针并且没有被覆盖。请参阅下面的完整答案。 【参考方案1】:

myArray 是在堆栈内存上创建的堆栈/自动变量。记住记忆永远存在。它只是由基于分配和释放的不同指针拥有。您仍然可以访问相同值的原因是同一块内存没有分配给另一个指针并且没有被覆盖。

评估它。创建另一个从堆栈分配相同数量但放置不同值的函数。或者在同一个函数中添加参数并使用不同的值调用它两次。然后你会看到不同之处。

#include <stdio.h>

int * vla(int n, int a, int b)
    int myArray[n];

    myArray[0] = a;
    myArray[1] = b;

    int * pointerToInt = myArray;
    return pointerToInt;


int main(void)

    int * pointerToInt = vla(10, 10, 11);
    vla(10, 20, 21); // over write stack

    printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 20, 21

    return 0;

顺便说一句,从vla 返回堆栈内存不是一个好主意。动态内存是使用malloc 系列函数从堆中分配的。

【讨论】:

【参考方案2】:

您仍然可以正确访问可变长度数组的第一个和第二个元素,因为您将 myArray 的基地址分配给 pointerToInt。自动变量只在块内有生命,但在这个程序中,我们使用指针来访问内存中的数据,只要该部分堆栈没有分配给任何其他程序,我们就可以访问该部分堆栈。如果堆栈的该部分分配给其他进程,我们将在尝试访问未经授权的内存时出现分段错误

【讨论】:

以上是关于在其内存应该已被释放后访问可变长度数组的主要内容,如果未能解决你的问题,请参考以下文章

C 可变长度数组存储持续时间

通过过度分配内存在结构中内联可变长度数组是不是有效?

分配数组 VS。可变长度数组[重复]

GoLang笔记-数组和切片,本质是就是长度不可变的可变的区别

创建一个具有可变长度数组的接口,其中包含 TypeScript/Angular4 中的对象

Delphi Setlength 内存释放总结