2015-03-22 2 views
1

Я не понимаю, почему этот код компилируется и затем: ошибки сегментацииC Segfault используя длинные целые

Есть те unsigned long с даже необходимо? Я также отметил, что если я изменю этот 21 на 18, он даст правильный результат. Код предназначен для того, чтобы найти LCM всех чисел от 1 до 20.

Запуск его в 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); 
+1

Вы пытались подключить отладчик и получить стек? Я предполагаю, что проблема слишком глубокая рекурсия в 'gcd()' – myaut

+0

@myaut Спасибо, я запускаю его с помощью 'gdb'. Я отредактирую вопрос с результатом. – rubik

+0

Похоже, вы правы. Как решить эту проблему? – rubik

ответ

2

Вы переполнением стека. Какой позор, потому что это должно быть легко оптимизировано как хвостовая рекурсия, полная рекурсия чрезвычайно переполнена для этого. Использование правильных уровней оптимизации в любом современном компиляторе (cl, gcc, icc) должно избавиться от segfault.

К счастью написания этого итеративно тривиально, как ад:

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

    return a; 
} 
+0

@myaut, когда строки коротки, все пробелы делают его менее читаемым imo. До вас все, хотя. – Blindy

+0

, когда большая часть кода следует стилю с помощью «пространственных операторов» (т. Е. PEP-8, Linux Kernel), делает его менее читаемым. И это ломает мозговой токенизатор;) – myaut

1

Из-за того, как стек и как они работают, есть предел того, насколько глубоко вызовов функций могут быть вложенными, в зависимости от того, как много локального состояния они хранят.

Для чрезвычайно несбалансированных аргументов, реализации gcd пути многократного вычитания требует много итераций, и поэтому ваша рекурсия идет сторонней глубже. Вам нужно либо изменить реализацию (например, сделать ее итеративной), либо изменить алгоритм (например, вычислить остатки вместо различий).

Вы можете увеличить размер стека, но это расточительно для памяти, а больший размер будет работать в конечном итоге также с большими входами.