【问题标题】:Segmentation fault when using recursive sum operation使用递归求和运算时出现分段错误
【发布时间】:2018-09-10 08:25:10
【问题描述】:

我在使用两种不同的递归求和方法时遇到问题,在某些时候都失败并返回分段错误错误。第一个,sum_a 只在高值上失败,通过了 260000,我不知道为什么,第二个 sum_b 总是失败。任何帮助将不胜感激。

谢谢

执行如下:./sum a x

其中 x 是 SUM(1:x) 所需的递归次数,a 是 a 或 b

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned count=0;

void signal_segv_handler(int sig) {
    char s[50];
    sprintf(s, "Segmentation fault! count=%u\n", count);
    write(2, s, strlen(s));
    _exit(1);
}

unsigned long long *sum_b(unsigned long long x) {
    unsigned long long *s;
    count++;
    if (x>0)
        *s = *sum_b(x - 1) + x;
    else
        *s = 0;
    return s;
}

unsigned long long sum_a(unsigned long long x) {
    count++;
    if (x>0)
        return sum_a(x - 1) + x;
    else
        return 0;
}

int main(int argc, char** argv) {
    unsigned long long x;
    unsigned long long *sum_result;
    char result[100];

    static char stack[SIGSTKSZ];
    stack_t ss = {
        .ss_size = SIGSTKSZ,
        .ss_sp = stack,
    };
    struct sigaction sa = {
        .sa_handler = signal_segv_handler,
        .sa_flags = SA_ONSTACK
    };
    sigaltstack(&ss, 0);
    sigfillset(&sa.sa_mask);
    sigaction(SIGSEGV, &sa, 0);

    if (argc < 3) {
        printf("Please specify the sum function to use (a or b) and the target number of integers to sum.\n");
        return -1;
    }
    x = atoi(argv[2]);

    if (strcmp(argv[1], "a") == 0)
        sprintf(result, "sum_a = %llu for x=%llu, count=%u \n", sum_a(x), x, count);
    else if (strcmp(argv[1], "b") == 0) {
        sum_result = sum_b(x);
        sprintf(result, "sum_b = %llu for x=%llu, count=%u \n", sum_result, x, count);
        free(sum_result);
    }
    else {
        printf("error: function must be a or b\n");
        return -1;
    }

    write(1, result, strlen(result));

    return 0;
}

【问题讨论】:

  • Sum_a 由于 stackoverflow 失败。您的方法堆栈会添加越来越多的方法,直到达到限制。
  • @Thomas 谢谢,但有什么限制?为什么总是在 260000 左右,我该如何解决?
  • 我不知道限制...我认为您可以在 IDE 中更改限制...
  • 但是你为什么要用递归来做呢?这只是一个总和......所以通常的循环也可以工作
  • 但是你为什么要用递归来做呢?这只是一个总和......所以通常的循环也可以工作

标签: c recursion sum segmentation-fault


【解决方案1】:
unsigned long long *sum_b(unsigned long long x) {
    unsigned long long *s; <------
    count++;
    if (x>0)
        *s = *sum_b(x - 1) + x;
    else
        *s = 0;
    return s;
}

您正在使用未初始化的指针,没有任何内存分配来存储总和结果。

【讨论】:

    【解决方案2】:

    当 sum_a 和 sum_b 的迭代消耗的内存超过堆栈中的可用内存时,它们都会导致堆栈溢出。似乎您的程序的堆栈大小为 8192KB(您可以在控制台中使用ulimit -s 进行检查),一次 sum_a 迭代消耗 32 个字节,而 sum_b 需要 48 个字节(因为变量比 sum_a - unsigned long long *s; 中的更多,并且可能 16 字节堆栈对齐我不确定),所以它们分别在 ~260k 和 ~170k 迭代时溢出堆栈。

    但是 sum_b 还有一点段错误,这里是*s = *sum_b(x - 1) + x;,这里是*s = 0;
    这是分配给一个未初始化的指针(野指针,它指向一个随机内存地址)。如果当然没有发生堆栈溢出,就会发生这种情况(在这种情况下,永远不会达到此行中的赋值操作)。

    一些与问题无关的评论:

    1. 你在主栈上分配alt栈,如果溢出了,你的handler状态不好,在某些情况下它仍然可以工作,但是你应该把static char stack[SIGSTKSZ];改成malloc函数。
    2. 您应该避免在信号处理程序中使用非信号安全函数,您可以在信号安全手册中找到函数列表。
    3. 此行可能不需要,你可以删除它sigfillset(&amp;sa.sa_mask);
    4. 另一个段错误:free(sum_result); 您应该始终平衡 malloc 和 free 调用。

    【讨论】:

      猜你喜欢
      • 2020-05-28
      • 1970-01-01
      • 2021-02-25
      • 2019-06-09
      • 2020-03-22
      • 2017-11-12
      • 2016-11-06
      • 2017-03-14
      相关资源
      最近更新 更多