【问题标题】:How can i remove this Segmentation fault in C Program如何在 C 程序中删除此分段错误
【发布时间】:2011-11-01 06:28:00
【问题描述】:

这里我想解决这段代码中的堆栈溢出问题。 在这段代码中,我递归调用函数 p 350000 次,所以我得到了分段错误 当我删除 350000 并放入 300000 时,它工作正常 这里的分段错误是因为我多次递归调用函数 p 或调用递归函数太深。

这不起作用,因为我接受了if(i != 350000)。 它的止损点可能在 300000 到 327480 这个范围内。我测试了 10 次

代码:

#include <stdio.h>

void p(char *, int);

int main() 
{
    char *a = "HI";
    int b = 10;
    p(a, b);
    printf("\nComplete");
    return 0;

}
void p(char *a, int b) 
{
    static long int i = 0;

    if (i != 350000) 
    {
        printf("\n%ld \t at Hi hello", i);
        i++;
        p(a, b);
    } else 
    {
        return;
    }
}

当我使用 valgrind 工具检查此代码时,valgrind 会报告这样的错误

==9236== Stack overflow in thread 1: can't grow stack to 0x7fe801ff8
==9236== 
==9236== Process terminating with default action of signal 11 (SIGSEGV)
==9236==  Access not within mapped region at address 0x7FE801FF8
==9236==    at 0x4EA012E: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1276)
==9236==  If you believe this happened as a result of a stack
==9236==  overflow in your program's main thread (unlikely but
==9236==  possible), you can try to increase the size of the
==9236==  main thread stack using the --main-stacksize= flag.
==9236==  The main thread stack size used in this run was 8388608.
==9236== Stack overflow in thread 1: can't grow stack to 0x7fe801ff0
==9236== 
==9236== Process terminating with default action of signal 11 (SIGSEGV)
==9236==  Access not within mapped region at address 0x7FE801FF0
==9236==    at 0x4A2269F: _vgnU_freeres (vg_preloaded.c:58)
==9236==  If you believe this happened as a result of a stack
==9236==  overflow in your program's main thread (unlikely but
==9236==  possible), you can try to increase the size of the
==9236==  main thread stack using the --main-stacksize= flag.
==9236==  The main thread stack size used in this run was 8388608.

请帮帮我,我真的想要这个问题的解决方案。而且我无法从我的代码中删除函数的递归调用。

【问题讨论】:

    标签: c memory memory-management stack-overflow


    【解决方案1】:

    堆栈不是无限资源。递归非常适用于相对较快地减少搜索空间的算法(排序数组的二进制切分、二进制或多路树遍历等)。

    如果您发现自己的算法需要递归到 35000 次,那么您真的应该重新考虑使用递归解决方案。

    例如:

    def addUnsigned (a, b):
        if a == 0:
            return b
        return addUnsigned (a-1, b+1)
    

    不是适合递归的。

    如果您真的无法移除递归,那么您需要按照 valgrind 的建议进行操作,更改堆栈大小。例如,我系统上的链接编辑器ld 有一个--stack 选项,允许您指定保留(以及,可选地,提交)堆栈大小。

    【讨论】:

    • 那么我如何知道当前堆栈大小并以编程方式重置堆栈大小
    • 你不要在程序里做,一般是由链接器或加载器来做。说真的,你需要重新审视你对递归的需求。
    • 回复我...我该怎么做?
    • 如果你使用 MACRO 而不是 thet 函数呢?
    • Sam,您需要查看链接器的选项。如果您使用ld,请尝试ld --help 以获取选项。您可能会在那里找到可以指定堆栈大小的东西。如果您要问如何将递归解决方案转换为迭代解决方案,最好在单独的问题中提出。
    【解决方案2】:

    对于那个特定的例子,如果你将编译器的优化级别调得足够高,它应该执行尾调用消除,这将解决堆栈溢出问题(例如,gcc 4.4.5 在-O2 及更高版本中这样做)。

    【讨论】:

      【解决方案3】:

      如果您仍想以编程方式控制它,您可以在线程中调用您的函数并设置线程的堆栈大小(并等待线程完成)。

      【讨论】:

        猜你喜欢
        • 2021-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2022-01-09
        • 2012-10-12
        • 2018-11-18
        相关资源
        最近更新 更多