簡體   English   中英

使用長整數的C段錯誤

[英]C segfault using long integers

我不明白為什么這個代碼編譯然后segfaults:

#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的所有數字的LCM。

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

你堆滿了。 這是一種恥辱,因為它應該很容易優化為尾遞歸,完全遞歸對此非常過分。 在任何現代編譯器(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;
}

由於堆棧及其工作原理,對函數調用的嵌套深度有限制,具體取決於它們保留的本地狀態。

對於極不平衡參數,實現gcd反復減法需要大量的迭代,所以你的遞歸去的方式 ,以深。 您需要更改實現(例如,使其迭代),或更改算法(例如,計算余數而不是差異)。

您可以增加堆棧大小,但這會浪費內存,並且較大的大小最終會在輸入較大的情況下耗盡。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM