使用长整数的 C 段错误
C segfault using long integers
我不明白为什么这段代码编译然后出现段错误:
#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
,它会给出正确的结果。该代码旨在找到从 1
到 20
.
所有数字的 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
需要 lot 次迭代,因此您的递归会 way 地深。您需要更改实现(例如使其迭代)或更改算法(例如计算余数而不是差异)。
您可以增加堆栈大小,但这会浪费内存,并且更大的大小将 运行 最终 运行 也会随着更大的输入而消失。
我不明白为什么这段代码编译然后出现段错误:
#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
,它会给出正确的结果。该代码旨在找到从 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);
您正在溢出堆栈。真可惜,因为那应该很容易优化为尾递归,完全递归对此非常矫枉过正。在任何现代编译器(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
需要 lot 次迭代,因此您的递归会 way 地深。您需要更改实现(例如使其迭代)或更改算法(例如计算余数而不是差异)。
您可以增加堆栈大小,但这会浪费内存,并且更大的大小将 运行 最终 运行 也会随着更大的输入而消失。