使用递归求和运算时出现分段错误

时间:2018-03-31 14:40:34

标签: c recursion sum segmentation-fault

我使用两种不同的递归求和方法遇到问题,在某些时候,这两种方法都会失败并返回分段错误错误。第一个,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;
}

2 个答案:

答案 0 :(得分:3)

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;
}

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

答案 1 :(得分:0)

当sum_a和sum_b的迭代消耗的内存超过堆栈中可用的内存时,它们都会导致堆栈溢出。看起来你的程序的堆栈大小是8192KB(你可以在控制台中用ulimit -s检查它),一个sum_a迭代消耗32个字节,sum_b需要48个字节(因为变量多于sum_a - {{1可能是16字节堆栈对齐,我不确定),因此它们分别在~260k和~170k迭代上流动堆栈。

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

有些评论与此问题无关:

  1. 你在主堆栈上分配alt堆栈,如果溢出,你的处理程序处于不良状态,它仍然可以在某些情况下工作,但你应该将*s = 0;更改为malloc函数。
  2. 您应该避免在信号处理程序中使用非信号安全功能,即信号安全人员可能找到的功能列表。
  3. 此行可能不是必需的,您可以将其删除static char stack[SIGSTKSZ];
  4. 另一个段错误:sigfillset(&sa.sa_mask);你应该始终平衡malloc和免费电话。