声明大型数组时出现堆栈溢出异常

Getting a stack overflow exception when declaring a large array

提问人:Patrick McDonald 提问时间:2/21/2009 最后编辑:Patrick McDonald 更新时间:1/10/2018 访问量:19952

问:

以下代码为我生成堆栈溢出错误

int main(int argc, char* argv[])
{
    int sieve[2000000];
    return 0;
}

我该如何解决这个问题?我正在使用 Turbo C++,但想将我的代码保留在 C 中

编辑:

谢谢你的建议。上面的代码只是举例来说,我实际上在函数中声明数组,而不是在 sub main 中声明数组。此外,我需要将数组初始化为零,所以当我在谷歌上搜索 malloc 时,我发现 calloc 非常适合我的目的。

与在堆栈上分配相比,Malloc/calloc 还有一个优势,即允许我使用变量声明大小。

C 数组 内存 堆栈 分配

评论

13赞 David Z 2/21/2009
我读到“堆栈溢出异常”,心想“......?网站有问题吗?显然我在这里花了太多时间:-/
5赞 Patrick McDonald 2/21/2009
我很确定这种类型的问题以前一定在这个网站上出现过,但是搜索“堆栈溢出”没有任何用处
4赞 MahlerFive 2/21/2009
我认为每个 C 程序员最终都会浪费大量时间第一次弄清楚这个问题。
2赞 phuclv 10/28/2013
Turbo C++ 是一个 16 位应用程序,这意味着它使用内存分段,每个段的大小为 64KB,因此任何结构都不能大于这个数字,并且总内存使用量最大为 640KB(使用一些扩展内存管理器时为 1MB 或更多)。为什么需要使用这样一个已有 20 多年历史的编译器?
1赞 ryyker 8/21/2019
到现在为止,希望您已经发现了 GCC。除其他外,它与Code::Blocks IDE捆绑在一起。

答:

66赞 arul 2/21/2009 #1

您的数组太大,无法放入堆栈中,请考虑使用堆:

int *sieve = malloc(2000000 * sizeof(*sieve));

如果您确实想更改堆栈大小,请查看此文档。

提示: - 不要忘记在不再需要动态分配的内存时释放它。

评论

24赞 aib 2/23/2009
由于这是 C,因此您不需要(实际上也不应该)强制转换 malloc 的返回值。
1赞 2/28/2009
你为什么不投射 malloc 的结果?难道你不必从虚空*中施放它才能用它做任何事情吗?
5赞 jweyrich 2/11/2011
@yodaj007:你不需要明确地投射它。由于赋值变量也是指针类型,因此赋值将执行隐式转换。
4赞 WhozCraig 8/27/2015
@Amy 阅读以下内容:“我是否投射了 malloc 的结果?它解释了为什么不在 C 中强制转换(或任何其他内存分配函数)的几个原因。malloc
0赞 Peter Cordes 11/5/2021
相关:C++ 规范问答答案,建议对同一问题进行新建/删除或 std::vector:大数组大小的分段错误
0赞 Cogsy 2/21/2009 #2

最好将其分配在堆上,而不是堆栈上。类似的东西

int main(int argc, char* argv[])
{
    int * sieve;
    sieve = malloc(20000);
    return 0;
}

评论

1赞 paulm 5/12/2014
并检查筛子是否为 NULL
0赞 DragonLord 7/31/2015
“我只是给你的筛子”--佐汉
4赞 Toby Speight 5/17/2018
我想你的意思是 - 除非你的平台有 1 大小(即便如此,我也不会在代码中嵌入这个假设)。sieve = malloc(20000 * sizeof *sieve)int
1赞 RandomNickName42 2/21/2009 #3

这大约是 7MB 的堆栈空间。在 Visual Studio 中,可以使用 /STACK:###,### 来反映所需的大小。如果你真的想要一个巨大的堆栈(这可能是一个很好的理由,使用LISP或其他:)的东西,在强制你使用VirtualAlloc之前,即使堆也仅限于小的分配),你可能还想将你的PE设置为使用/LARGEADDRESSAAWARE(再次是Visual Studio的链接器)进行构建,但这会配置你的PE头文件,以允许你编译的二进制文件寻址完整的4GB的32位地址空间(如果在WOW64中运行)。如果生成真正庞大的二进制文件,通常还需要将 /bigobj 配置为额外的链接器参数。

如果你仍然需要更多的空间,你可以通过使用类似于(同样是 MSVC 的链接)/merge: 的东西来从根本上违反约定,这将允许你将一个部分打包到另一个部分,这样你就可以将每个字节用于单个共享代码/数据部分。当然,您还需要在 def 文件中或使用 #pgrama 配置 SECTIONS 权限。

15赞 qrdl 2/21/2009 #4

有 3 种方法:

  1. 在堆上分配数组 - 使用,正如其他海报所建议的那样。不要忘记它(尽管这并不那么重要 - 操作系统将在程序终止时为您清理内存)。malloc()free()main()
  2. 在单位级别声明数组 - 它将在数据段中分配,并且对每个人都可见(添加到声明将限制对单位的可见性)。static
  3. 将数组声明为 - 在这种情况下,它将在数据段中分配,但仅在 中可见。staticmain()

评论

1赞 Christoph 2/21/2009
我只是让它静态:应该只调用一次,所以没有陷阱;这里不需要...main()malloc()
-1赞 Tim Post 2/21/2009 #5

有没有原因不能使用 alloca() 根据对象实际需要的大小在堆栈框架上分配所需的空间?

如果你这样做了,但仍然破坏了堆栈,把它放在分配的堆里。我强烈建议不要在 main() 中将其声明为静态并将其放在数据段中。

如果它真的必须那么大,而你的程序不能在堆上分配它,那么你的程序一开始就没有在这种类型的机器上运行的业务。

你(确切地)想完成什么?

评论

0赞 Patrick McDonald 2/22/2009
我正在使用 ProjectEuler.net 中的问题来学习 C,并且正在实现 Sieve of Eratosthenes 算法,所以它必须那么大。不过,malloc 对我的目的来说效果很好
1赞 asdf 2/22/2009 #6

使用 malloc。全部检查返回类型是否为 null,如果它为 null,则您的系统根本没有足够的内存来容纳那么多值。

0赞 Ivan Rubinson 7/4/2016 #7

你的阵列很大。

您的计算机或操作系统可能没有或不想分配这么多内存。


如果你绝对需要一个巨大的数组,你可以尝试动态分配它(使用 ),但这样你就有泄漏内存的风险。不要忘记释放内存。malloc(...)

malloc 的优点是它尝试在堆上分配内存,而不是在堆栈上分配内存(因此您不会得到堆栈溢出)。

您可以检查 malloc 返回的值,以查看分配是成功还是失败。 如果失败了,只需尝试 malloc 一个较小的数组。


另一种选择是使用可以动态调整大小的不同数据结构(如链表)。此选项是否有效取决于您将如何处理数据。

另一种选择是将内容存储在文件中,即时流式传输数据。这种方法是最慢的。

如果您要在硬盘驱动器上存储,您不妨使用现有的库(用于数据库)

0赞 Arun Chettoor 7/14/2017 #8

由于 Turbo C/C++ 是 16 位编译器,int 数据类型消耗大约 2 个字节。 2字节*2000000=40,00,000字节=3.8147MB空间。

函数的自动变量存储在堆栈中,它导致了堆栈内存的溢出。相反,使用数据存储器 [使用静态或全局变量] 或动态堆内存 [使用 malloc/calloc] 根据处理器内存映射的可用性创建所需的内存。