可变长度数组是在堆上创建的,但是我们无法释放它们?

时间:2015-08-12 08:40:37

标签: c arrays

我已经验证了在堆上创建了可变长度数组(参见下面的代码),但是我们不能使用自由操作来释放它们(导致故障陷阱6)。

我被告知堆由用户管理,因此如果我们不需要它们,我们必须在堆上显式释放任何东西。那么谁将负责释放这些记忆?这是C的缺陷吗?

在堆上创建显示可变长度数组的代码。 (平台:Mac OS X,gcc,64位)

#include<stdio.h>
#include<stdlib.h>
int main(int argc, char **argv)
{
    int n = atoi(argv[1]);
    int a1[10];
    int a2[n];
    int a3[10];

    printf("address for a1:%p,address for a2:%p, address for a3:%p\n",a1,a2,a3);
    printf("a1-a2: %lx, a1-a3: %lx\n",(a1-a2),(a1-a3));

    //free(t); // will cause fault trap 6

    return 0;
}

结果是:

$ ./run 10
address for a1:0x7fff5d095aa0,address for a2:0x7fff5d0959e0, address for a3:0x7fff5d095a70
a1-a2: 30, a1-a3: c

很明显a1和a3是连续的,因此在堆栈上,但a2的地址较低,因此在堆上。

3 个答案:

答案 0 :(得分:2)

可变长度数组具有自动存储持续时间,并具有块范围或函数原型范围。

所以这个数组

int a2[n];

具有自动存储持续时间和函数main的块范围。它不是在堆中创建的。当控件退出块作用域时,编译器会生成相应的代码以释放数组的已分配内存。

根据C标准(6.2.4对象的存储持续时间)

  

7对于这样一个具有可变长度数组类型的对象,它   生命周期从对象的声明延伸到执行   程序离开了声明的范围.35)如果范围是   以递归方式输入,每个都创建一个新的对象实例   时间。对象的初始值是不确定的。

您可以将函数free仅应用于使用malloc,calloc或realloc之类的内存分配函数分配的对象。

答案 1 :(得分:2)

实现如何为VLA分配存储是实现定义的。 VLA具有自动存储持续时间,您不应尝试free()它。 出于所有实际目的,您应该像处理任何其他局部变量一样对待它。

您只使用malloc()系列函数释放()您分配的内存。

所有实现都不支持VLA,它是一种条件功能。

_ _STDC_NO_VLA_ _

用于测试是否支持VLA(如果不支持VLA,则不支持VLA)。

在我看来,不应该使用VLA主要是因为:

  • 它们在C11中是可选的
  • 分配失败不可移动检测

答案 2 :(得分:2)

  

这是C的缺陷吗?

绝对不是。你做了几个错误的假设,这会导致你得出错误的结论。

首先,让我们直接使用术语:&#34; stack&#34;被称为自动存储区; &#34;堆&#34;被称为动态存储区域。 C标准不对下列任何事项提出任何要求:

  • 自动和动态区域中地址的相对顺序
  • 同一存储区域内商品地址的相对顺序
  • 同一区域内分配之间是否存在差距

这使得无法仅通过查看数字地址来确定变量是在自动区域还是在动态区域中,而无需进行猜测。特别是,显而易见的&#34;显而易见的&#34;对你而言,与实际发生的事情毫无关系。

  

那么谁将负责释放这些记忆?

您有责任在动态存储区域中分配的所有内容上调用free。您没有在动态存储区 * 中分配可变长度数组,因此您不负责在其上调用free

* 如果编译器实现要在动态存储区域中分配VLA,编译器将负责在该指针上调用free