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

roejwanj  于 2022-12-26  发布在  其他
关注(0)|答案(9)|浏览(118)

今天我在帮我的一个朋友写一些C代码,我发现了一些奇怪的行为,我无法解释为什么会发生。我们有一个TSV文件,里面有一个整数列表,每行有一个int。第一行是列表的行数。
我们还有一个C文件,里面有一个非常简单的“readfile”。第一行被读到n,行数,然后有一个初始化:

int list[n]

最后是nfscanf的for循环。
对于小的n(直到~100.000),一切都很好,然而,我们发现当n很大(10^6)时,就会发生一个分段故障。
最后,我们将列表初始化更改为

int *list = malloc(n*sizeof(int))

一切都很好,即使是非常大的n
有人能解释一下为什么会发生这种情况吗?是什么导致了int list[n]的segfault,当我们开始使用list = malloc(n*sizeof(int))时,它被停止了?

6za6bjd0

6za6bjd01#

这里有几个不同的部分在起作用。
第一个是将数组声明为

int array[n];

以及

int* array = malloc(n * sizeof(int));

在第一个版本中,我们声明了一个具有自动存储持续时间的对象,这意味着数组只在调用它的函数存在时才存在;在第二个版本中,我们获取了具有动态存储持续时间的内存,这意味着它将一直存在,直到用free显式地释放它。
第二个版本在这里工作的原因是C通常是如何编译的实现细节。通常,C内存被分成几个区域,包括堆栈(用于函数调用和局部变量)和堆(用于malloc ed对象)。堆栈通常比堆小得多。通常是8 MB左右。因此,如果您尝试使用

int array[n];

那么你可能会超出栈的存储空间,导致segfault.另一方面,堆通常有很大的空间(比如说,和系统上的空闲空间一样大),所以malloc ing一个大对象不会导致内存不足的错误.
一般来说,在C中使用变长数组要小心,因为它们很容易超过堆栈大小。除非你知道大小很小,或者你真的只想在很短的时间内使用数组,否则首选malloc

khbbv19g

khbbv19g2#

int list[n]

在堆栈上为n整数分配空间,这个空间通常很小。在堆栈上使用内存比另一种方法快得多,但是它很小,而且很容易溢出堆栈(即分配了太多的内存),如果你做了像分配巨大的数组或递归太深的事情。你不必手动释放以这种方式分配的内存,当数组超出范围时,编译器会执行此操作。
另一方面,mallocheap 中分配空间,与堆栈相比,* heap * 通常是 * 非常大的 *。您将不得不在堆上分配大量的内存来耗尽它,但是在堆上分配内存比在堆栈上分配要慢得多,并且当您使用完它时,必须通过free手动释放它。

wqsoz72f

wqsoz72f3#

int list[n]将数据存储在堆栈中,而malloc将数据存储在堆中。
堆栈是有限的,没有太多的空间,而堆要大得多。

hwazgwia

hwazgwia4#

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

mm9b1k5b

mm9b1k5b5#

此声明在堆栈上分配内存

int list[n]

malloc在堆上分配。
堆栈大小通常比heap小,所以如果你在堆栈上分配了太多的内存,你会得到一个堆栈溢出。
另请参见this answer for further information

5w9g7ksd

5w9g7ksd6#

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

int list[n]

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

int *list = malloc(n*sizeof(int))

在堆上分配内存。
在栈的情况下,它们可以增长的大小通常是有限制的(如果它们可以增长的话),在堆的情况下,仍然有限制,但这往往是非常大的,并且(广泛地)受到RAM+交换+地址空间的限制,通常至少是一个数量级以上,如果不是更多的话。

70gysomp

70gysomp7#

如果你在linux上,你可以把ulimit -s设置成一个更大的值,这也可以用于栈分配.当你在栈上分配内存时,内存会一直保留到函数执行结束.如果你在堆上分配内存(使用malloc),你可以在任何时候释放内存(甚至在函数执行结束之前).
通常,堆应该用于大内存分配。

4c8rllxm

4c8rllxm8#

当您使用malloc分配内存时,内存是从堆而不是从堆栈分配的,堆栈的大小受到更多的限制。

n3schb8v

n3schb8v9#

int array[n];

这是一个静态分配数组的例子,在编译时数组的大小是已知的,并且数组将在堆栈上分配。

int *array(malloc(sizeof(int)*n);

这是一个动态分配数组的例子,数组的大小在运行时是用户已知的,并且数组是在堆上分配的。

相关问题