使用长整数的C段错误

时间:2015-03-22 13:33:33

标签: c segmentation-fault

我不明白为什么这段代码编译然后是段错误:

#include <stdio.h>
#include <stdlib.h>

unsigned long int gcd(unsigned long int, unsigned long int);
unsigned long int lcm(unsigned long int, unsigned long int);

int main(int argc, char *argv[]) {
    int i;
    unsigned long int n = 1L;
    for (i = 2; i < 21; i++) {
        n = lcm(n, i);
    }
    printf("%ld\n", n);
    return 0;
}

unsigned long int gcd(unsigned long int a, unsigned long int b) {
    if (a == b) return a;
    if (a > b) return gcd(a - b, b);
    return gcd(a, b - a);
}

unsigned long int lcm(unsigned long int a, unsigned long int b) {
    return abs(a * b) / gcd(a, b);
}

那些unsigned long是否必要?我还注意到,如果我将21更改为18,则会给出正确的结果。该代码旨在查找从120的所有数字的最小公倍数。

gdb中运行它:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400643 in gcd (a=7536618, b=18) at p5.c:19
19    if (a > b) return gcd(a - b, b);

2 个答案:

答案 0 :(得分:2)

你堆满了。这是一种耻辱,因为它应该很容易优化为尾递归,完全递归对此非常过分。在任何现代编译器(cl,gcc,icc)中使用适当的优化级别应该摆脱段错误。

幸运的是,迭代地写这个很简单就像地狱一样:

unsigned long gcd(unsigned long a, unsigned long b) 
{ 
  while(a != b)
    if(a > b)
       a -= b;
    else 
       b -= a;

  return a;
}

答案 1 :(得分:1)

由于堆栈的工作原理以及它们的工作原理,对函数调用的嵌套深度有限制,具体取决于它们保留的本地状态。

对于极不平衡的参数,通过重复减法实现gcd需要迭代的批次,因此您的递归 way 深入。您需要更改实现(例如,使其迭代),或更改算法(例如,计算余数而不是差异)。

您可以增加堆栈大小,但这会浪费内存,并且较大的大小最终会在输入较大的情况下耗尽。