我无法理解这个代码在运行时是如何导致段错误的,有人能帮我理解发生了什么吗?
#include <stdio.h>
unsigned long long factorial(unsigned long long x, unsigned long long amt)
{
if (x == 1ULL) return amt;
else return factorial(x-1ULL, amt*x);
}
int main(int argc, char *argv[])
{
for (unsigned long long i = 0; i < 10ULL ;i++) {
printf("%llu\n", factorial(i, 1ULL));
}
}
答案 0 :(得分:2)
在原始代码中:
if (x == 1ULL) return amt;
意味着此递归函数factorial
的退出条件。但是,当将值0传递给函数并且假定x
的类型为unsigned long long
时,将首先使用参数factorial
对函数x-1ULL
进行递归调用x
的值非常大(18446744073709551615就是我在这里得到的)。对factorial
的连续递归调用将逐渐耗尽为程序分配的堆栈空间,直至出现分段错误。
你应该这样做:
#include <stdio.h>
unsigned long long factorial(unsigned long long x, unsigned long long amt)
{
if (x == 0ULL) // Changed the exit condition, see Reference [1]
return amt; // Bear in mind that the initial value for amt you passed is 1
amt*=x; // See Reference [2]
return factorial(x-1ULL, amt);
}
int main(int argc, char *argv[]) {
for (unsigned long long i = 0; i < 10ULL ;i++) {
printf("%llu\n", factorial(i, 1ULL));
}
}
<强>参考强>
factorial(x-1ULL, amt*x)
注意强>
ULL
后缀在这里是多余的,可以完全删除。
答案 1 :(得分:2)
首先,段错误不一定导致指针解除引用无效。在这种情况下,它实际上是由无限递归和最终耗尽堆栈空间引起的。为什么?递归函数的基本要求是它必须在某种状态下完成和终止递归,如果仔细查看代码,在函数factorial
中,如果x
为0,则递归将变为无穷无尽并最终崩溃你的程序。您可以通过将终止条件更改为:
if (x <= 1ULL) return amt;