数组类型与使用malloc分配的数组之间的区别


70

今天,我用一些C代码帮助了我的一个朋友,但我发现了一些奇怪的行为,无法解释他为什么会这样。我们有一个TSV文件,其中包含一个整数列表,int每行一行。第一行是列表中的行数。

我们也有一个带有非常简单的“ readfile”的ac文件。第一行被读取为n,即行数,然后进行了以下初始化:

最后一个为环nfscanf

对于小n(直到〜100.000),一切都很好。但是,我们发现,当n大(10 ^ 6)时,将发生段错误。

最后,我们将列表初始化更改为

一切都很好,即使很大n

有人可以解释为什么会这样吗?是什么引起的段错误int list[n],在我们开始使用时已停止list = malloc(n*sizeof(int))


正是我在寻找什么,我在harckerank数组操纵问题中遇到了同样的问题。
卡皮尔

Answers:


161

这里有几个不同的作品。

首先是将数组声明为

在第一个版本中,您要声明一个具有自动存储持续时间的对象。这意味着数组仅在调用它的函数存在的情况下存在。在第二个版本中,您将获得具有动态存储持续时间的内存,这意味着内存将一直存在,直到用显式释放为止free

第二个版本在这里起作用的原因是通常如何编译C的实现细节。通常,C内存分为几个区域,包括堆栈(用于函数调用和局部变量)和堆(用于malloced对象)。堆栈的大小通常比堆小得多。通常大约是8MB。结果,如果您尝试使用

然后,您可能会超出堆栈的存储空间,从而导致段错误。另一方面,堆通常具有很大的大小(例如,系统上的可用空间尽可能多),因此,堆malloc大对象不会导致内存不足错误。

通常,请注意C中的可变长度数组。它们很容易超过堆栈大小。身高:malloc除非你知道的大小是小还是,你真的只能做想要的短时间的阵列。

希望这可以帮助!


2
好答案!我想知道速度是否也有差异?
Tropilio

1
由于引用的局部性的影响,我怀疑堆栈分配的数组访问速度更快,而malloc其本身比仅碰撞堆栈指针要慢得多。但实际上,最好使用更适合手头任务的方法。
templatetypedef

或者,如果您声明int arr [1000000]; 在任何函数之外,它们会自动设置为零,并将存储在堆中。
DSOI__UNUNOCTIUM

@DSOI__UNUNOCTIUM这些数组将具有静态存储持续时间。您确定将它们存储在堆中吗?
templatetypedef

我之前分配的数组大小达数十万。我现在将对其进行测试。
DSOI__UNUNOCTIUM

10

在堆栈n上为整数分配空间,该空间通常很小。在堆栈上使用内存比替代方法要快得多,但是它非常小,如果您执行诸如分配大型数组或执行深度递归的操作,则很容易使堆栈溢出(即分配过多的内存)。您不必手动释放以这种方式分配的内存,当数组超出范围时,它由编译器完成。

malloc另一方面,在堆中分配空间,与堆栈相比,该空间通常很大。您将不得不在堆上分配大量内存以耗尽其内存,但是在堆上分配内存的速度比在堆栈上分配的速度要慢得多,并且必须在使用完后手动free将其分配。


1
“在堆栈上使用内存比其他方法快得多”,这是指“分配”还是“访问”?AFAIK,堆栈分配要快得多,但是它对访问(读/写)是否也适用?谢谢
dragonxlwang


1

int list[n]是一个VLA,它在堆栈而不是堆上分配。您不必释放它(它在函数调用结束时自动释放),并且分配迅速,但是您发现,存储空间非常有限。您必须在堆上分配更大的值。


1

该声明在堆栈上分配内存

malloc在堆上分配。

堆栈大小通常小于堆大小,因此,如果在堆栈上分配过多的内存,则会出现堆栈溢出。

另请参阅此答案以获取更多信息


1

假设您的实现中有一个典型的实现,则很可能是:

堆栈中的已分配列表,其中为:

在堆上分配的内存。

对于堆栈,通常会限制它们可以增长到多大(如果它们可以完全增长)。对于堆,仍然有一个限制,但通常会更大,并且(广泛地)受您的RAM + swap +地址空间的约束,该空间通常至少大一个数量级(如果不是更大的话)。


0

当您使用分配时malloc,内存是从堆分配的,而不是从堆栈分配的,这在大小上要受限制得多。


0

如果您使用的是Linux,则可以将ulimit -s设置为更大的值,这也可能适用于堆栈分配。当您在堆栈上分配内存时,该内存将一直保留到函数执行结束为​​止。如果在堆上分配内存(使用malloc),则可以随时释放内存(甚至在函数执行结束之前)。

通常,堆应用于大内存分配。


0

它是静态分配的数组的一个示例,在编译时将知道数组的大小。并且该数组将在堆栈上分配。

这是动态分配的数组的示例,并且在运行时用户将知道数组的大小。并且该数组将在堆上分配。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.