在主函数中,C语言的最大大小是多少?

5

可能重复:
C编程,为什么这个大数组声明会产生分段错误?

这是我第一次来这里,所以如果我打破了一些规定或者这个问题之前已经被解决过,请见谅。 我最近写了一个 C 程序,在其中我有一个矩阵:

char buff[NR][1024*1024];

我需要NR = 128。因此,程序将分配128MB内存。这是在main()函数中。我在几个具备足够内存的系统上测试了它,并且编译时没有错误。但在运行时,所有系统都报告分段错误。当NR = 7时它能工作,但当NR = 8时就不能工作。 我将该代码移到main()函数之外,使其成为全局变量。即使是128,它也不再崩溃。 有人知道为什么会出现这种情况吗? 编译器是GCC


可能是C编程,为什么这个大数组声明会导致分段错误?的重复问题。 - James McNellis
6个回答

16

问题在于你正在溢出堆栈,它通常只有几兆字节的大小(确切的大小取决于系统和编译器选项)。相反,你可以使用malloc在堆上分配内存。


1
@SB:是的,抱歉!现在已经修复了。@akira:我不建议将堆栈大小增加到128MB。 - Mark Byers
Linux上的堆栈默认为8兆,可以通过ulimit轻松更改。1兆似乎非常小...当然,这并不保证。 - R.. GitHub STOP HELPING ICE
2
@JAB,是的,全局变量非常糟糕。我会说,最佳实践规则中排名第一的是永远不要使用全局变量。(当然,全局常量表是可以的。)如果你需要一个太大而无法在堆栈上可靠分配的对象,请使用malloc - R.. GitHub STOP HELPING ICE
2
甚至可以通过添加“static”存储类限定符将其放在静态内存中。 - atzz
@Mark Byers:我也不会。 - akira
显示剩余7条评论

5
当您将其放入main()中时,它会在堆栈上分配128MB的空间,而堆栈通常是有限制的,不同的系统限制也不同。有些可能只允许您使用8MB,而其他一些则可以使用尽可能多的空间 - 您的限制似乎为8MB,这是大多数Linux平台的标准。如果这是类POSIX环境,则可以尝试使用ulimit -s来控制限制。
当您将声明从main()中取出并使其成为静态变量时,它将位于BSS段中(除非您对其进行初始化),并且在大多数系统上仅受堆空间的限制(堆空间通常非常大和/或无限制)。请参见http://en.wikipedia.org/wiki/Data_segment 但是,如果您想要局部和临时的解决方案,请考虑自行分配NR兆字节的空间:
#define MB (1024*1024)
char *bufp = malloc(NR*MB)
char *buf[NR];
int i;

for (i = 0; i < NR; i++)
  buf[i] = bufp + i*MB;

你也可以单独分配每个MB块,但我这样做是为了让整个区域在内存中连续。记得在完成后使用free(bufp)释放内存,如果你正在编写一个库或者程序将继续执行其他操作。


如果你正在编写一个库或者你的程序将继续执行其他操作,那么在使用free()时请加上“if you're writing a library of if your program will move on to do something else.”这样的说明。 - R.. GitHub STOP HELPING ICE

1

你的数组是在栈上分配的。栈有限制大小(取决于操作系统和链接器设置)。我认为win32(msvc编译器)的默认堆栈大小约为1兆字节,而linux(gcc)的默认堆栈大小约为8兆字节。任何大于此大小的内容都会导致堆栈溢出,从而导致立即段错误。

可能的解决方案:

  1. 在链接器设置中增加堆栈大小。
  2. 动态分配内存(使用malloc)。
  3. 将数组设为全局变量。
  4. 将数组设为静态变量。

将变量设为全局/静态变量会导致(至少在我看到的编译器中)它被分配在堆或代码段之外,这不会影响堆栈大小。


0

或者您可以增加程序的堆栈分配大小。例如,在VS 2008中,转到项目属性 -> 链接器 -> 并设置堆栈提交大小。


我不同意这个想法(但我不会给你投反对票)。堆栈不是存放大量数据的合适位置。 - tomlogic

0

你可以使用malloc,通常也可以在main函数外部使用文件作用域进行声明。如果你需要在另一个c文件中使用它,请考虑使用extern。除非你有一个非常好的理由拥有一个文件作用域变量(注意c实际上没有“全局”变量,只有可以通过extern访问的文件作用域变量),否则不建议使用此方法。这些技术方面,Google是你的朋友 :)。你还可以通常找到与编译器/操作系统相对应的最大堆栈大小设置。寻找“设置堆栈大小”。同样不建议使用,学会使用malloc :)。


-4

段错误可能有另外一个原因。使用诸如 gdb 的调试器来确定段错误发生的确切位置。


1
不,程序几乎肯定是因为那一行崩溃了。那段代码几乎总是会导致崩溃,通常会出现堆栈溢出错误或分段错误,这取决于编译器。 - Brian
仅仅因为那一行代码的存在,程序才会出错。当我将其注释掉后,程序就可以正常运行了。 - Iustin
如果你将其注释掉并且它正常运行,那么这具体有什么影响? - Puppy
我不太明白你的问题。我从代码中删除了这一行,程序没有引起分段错误。 - Iustin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接