【问题标题】:Getting a stack overflow exception when declaring a large array声明大型数组时出现堆栈溢出异常
【发布时间】:2023-01-17 21:45:54
【问题描述】:

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

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

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

编辑:

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

Malloc/calloc 也比在堆栈上分配有优势,允许我使用变量声明大小。

【问题讨论】:

  • 我读到“stack overflow exception”并心想“......?网站有问题吗?”显然我在这里花了太多时间 :-/
  • 我很确定这种类型的问题以前一定在这个网站上出现过,但是搜索“堆栈溢出”是没有用的
  • 我认为每个 C 程序员最终都会在第一次解决这个问题时浪费大量时间。
  • Turbo C++ 是一个 16 位应用程序,这意味着它使用内存分段,每个段的大小为 64KB,因此任何结构都不能大于此数字,总内存使用量最大为 640KB(某些扩展内存管理器为 1MB 或更多) ).为什么要用这么一个20多岁的编译器?
  • 到目前为止,希望您已经发现了 GCC。在其他地方它捆绑了Code::Blocks集成开发环境。

标签: c arrays memory stack allocation


【解决方案1】:

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

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

如果你真的想改变堆栈大小,take a look at this document.

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

【讨论】:

  • 因为这是 C,你不需要(事实上,不应该)转换 malloc 的返回值。
  • 为什么不转换 malloc 的结果?难道你不需要从 void* 中转换它来做很多事情吗?
  • @yodaj007:你不需要显式地转换它。由于赋值的变量也是指针类型,因此赋值执行隐式转换。
  • @Amy 读这个:"Do I cast the result of malloc?"。它解释了几个原因不是在 C 中转换 malloc(或任何其他内存分配函数)。
  • 相关:针对同一问题建议新建/删除或 std::vector 的 C++ 规范问答答案:Segmentation fault on large array sizes
【解决方案2】:

有3种方式:

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

【讨论】:

  • 我只是让它静态化:main() 应该只被调用一次,所以没有陷阱;这里不需要malloc()...
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    使用 malloc。所有检查返回类型不为空,如果它为空,那么您的系统根本没有足够的内存来容纳那么多值。

    【讨论】:

      【解决方案5】:

      你最好把它分配在堆上,而不是堆栈上。就像是

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

      【讨论】:

      • 并检查筛子是否为 NULL
      • “我只为你筛”——佐汉
      • 我认为您的意思是 sieve = malloc(20000 * sizeof *sieve) - 除非您的平台具有大小为 1 的 int(即便如此,我也不会将该假设嵌入代码中)。
      【解决方案6】:

      你的数组很大。

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


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

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

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


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

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

      如果你想在硬盘上存储,你也可以使用现有的库(用于数据库)

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          是否有某些原因导致您不能使用 alloca() 根据对象实际需要的大小在堆栈帧上分配所需的空间?

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

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

          你(究竟)想要完成什么?

          【讨论】:

          • 我正在使用 ProjectEuler.net 中的问题来学习 C,并且正在实施埃拉托色尼筛法算法,所以它确实有那么大。尽管 malloc 对我来说工作得很好
          猜你喜欢
          • 2022-01-02
          相关资源
          最近更新 更多