数组类型和用 malloc 分配的数组的区别
Posted
技术标签:
【中文标题】数组类型和用 malloc 分配的数组的区别【英文标题】:Difference between array type and array allocated with malloc 【发布时间】:2012-05-21 11:28:02 【问题描述】:今天我正在帮助我的一个朋友编写一些 C 代码,我发现了一些奇怪的行为,我无法向他解释为什么会发生这种情况。我们有一个包含整数列表的 TSV 文件,每行有一个 int
。第一行是列表的行数。
我们还有一个带有非常简单的“readfile”的 c 文件。第一行读到n
,行数,然后有一个初始化:
int list[n]
最后是 n
和 fscanf
的 for 循环。
对于小的 n(直到 ~100.000),一切都很好。但是,我们发现当 n 很大时(10^6),会发生段错误。
最后,我们将列表初始化改为
int *list = malloc(n*sizeof(int))
一切顺利,即使n
很大。
有人可以解释为什么会这样吗?是什么导致了int list[n]
的段错误,当我们开始使用list = malloc(n*sizeof(int))
时它停止了?
【问题讨论】:
正是我正在寻找的,我在 harckerank 数组操作问题中遇到了同样的问题。 【参考方案1】:int list[n] 将数据存储在堆栈中,而 malloc 将其存储在堆中。
栈是有限的,空间不大,而堆要大很多。
【讨论】:
【参考方案2】:int list[n]
是一个 VLA,它在堆栈上而不是在堆上分配。您不必释放它(它会在函数调用结束时自动释放)并且它分配得很快,但存储空间非常有限,正如您所发现的。您必须在堆上分配更大的值。
【讨论】:
【参考方案3】:这个声明在栈上分配内存
int list[n]
malloc 在堆上分配。
堆栈大小通常比堆小,因此如果您在堆栈上分配太多内存,则会出现堆栈溢出。
另见this answer for further information
【讨论】:
【参考方案4】:当您使用malloc
进行分配时,内存是从堆而不是从堆栈分配的,堆栈的大小受到更多限制。
【讨论】:
【参考方案5】:int list[n]
在堆栈上为n
整数分配空间,这通常非常小。在堆栈上使用内存比替代方案快得多,但它非常小,如果您执行分配大数组或递归太深等操作,很容易溢出堆栈(即分配太多内存)。您不必手动取消分配以这种方式分配的内存,当数组超出范围时由编译器完成。
malloc
在堆中分配空间,与堆栈相比,通常非常大。您将不得不在堆上分配更多的内存来耗尽它,但是在堆上分配内存比在堆栈上分配内存要慢得多,并且您必须通过 free
手动解除分配使用它。
【讨论】:
“在堆栈上使用内存比其他方式快得多”,这里是指“分配”还是“访问”? AFAIK,堆栈分配要快得多,但它也适用于访问(读/写)吗?谢谢【参考方案6】:这里有几个不同的部分。
首先是声明数组为的区别
int array[n];
和
int* array = malloc(n * sizeof(int));
在第一个版本中,您声明了一个具有自动存储期限的对象。这意味着该数组仅在调用它的函数存在时才存在。在第二个版本中,您将获得具有动态存储持续时间的内存,这意味着它会一直存在,直到它被 free
显式释放。
第二个版本在这里工作的原因是 C 通常如何编译的实现细节。通常,C 内存分为几个区域,包括堆栈(用于函数调用和局部变量)和堆(用于malloc
ed 对象)。堆栈的大小通常比堆小得多;通常它是8MB之类的东西。因此,如果您尝试使用
int array[n];
那么你可能会超出堆栈的存储空间,导致段错误。另一方面,堆通常具有很大的大小(例如,与系统上的可用空间一样多),因此malloc
ing 一个大对象不会导致内存不足错误。
一般来说,小心 C 中的可变长度数组。它们很容易超过堆栈大小。首选malloc
,除非你知道它的大小很小,或者你真的只想要这个数组很短的时间。
希望这会有所帮助!
【讨论】:
很好的答案!我想知道速度是否也有差异? 由于引用局部性的影响,我怀疑堆栈分配的数组访问速度更快,而malloc
本身比仅仅碰撞堆栈指针要慢得多。但实际上,最好使用更适合手头任务的任何方法。
或者,如果你声明 int arr[1000000];在任何函数之外,它们会自动设置为零并将存储在堆中。
@DSOI__UNUNOCTIUM 这些阵列将具有静态存储持续时间。您确定它们会存储在堆上吗?
我之前已经分配了大小高达几十万的数组。我现在就测试一下。【参考方案7】:
假设您的实现中有一个典型的实现,很可能是:
int list[n]
堆栈上的已分配列表,其中:
int *list = malloc(n*sizeof(int))
在您的堆上分配内存。
在堆栈的情况下,它们可以增长到多大通常是有限制的(如果它们可以增长的话)。在堆的情况下仍然有一个限制,但这往往在很大程度上受到您的 RAM + 交换 + 地址空间的限制,这通常至少大一个数量级,如果不是更多的话。
【讨论】:
【参考方案8】:如果您使用的是 linux,您可以将 ulimit -s 设置为更大的值,这也可能适用于堆栈分配。 当您在堆栈上分配内存时,该内存将一直保留到函数执行结束。如果您在堆上分配内存(使用 malloc),您可以随时释放内存(甚至在函数执行结束之前)。
一般来说,堆应该用于大内存分配。
【讨论】:
【参考方案9】: int array[n];
这是一个静态分配数组的例子,在编译时数组的大小是已知的。并且数组会被分配到栈上。
int *array(malloc(sizeof(int)*n);
这是一个动态分配数组的例子,数组的大小将在运行时为用户所知。并且数组会被分配到堆上。
【讨论】:
以上是关于数组类型和用 malloc 分配的数组的区别的主要内容,如果未能解决你的问题,请参考以下文章