C 递归函数有一些限制吗?这个功能需要多少层?
制作了一个递归函数,给出了给定起始数字的collatz序列中有多少项,这是代码n=13,例如:C 递归函数有一些限制吗?这个功能需要多少层?,c,recursion,stack-overflow,collatz,C,Recursion,Stack Overflow,Collatz,制作了一个递归函数,给出了给定起始数字的collatz序列中有多少项,这是代码n=13,例如: int collatz(long n,long o) { if (n!=1) { if(n%2==0) return collatz(n/2,o+1); else return collatz((n*3)+1,o+1); } else printf("%ld\t",o); } void ma
int collatz(long n,long o)
{
if (n!=1) {
if(n%2==0)
return collatz(n/2,o+1);
else
return collatz((n*3)+1,o+1);
} else
printf("%ld\t",o);
}
void main()
{
collatz(13,0);
}
函数按预期运行;但是,对于一些整数,例如“n=113383”,有些东西溢出(我猜)并返回:
Process returned -1073741571 (0xC00000FD) execution time : 4.631 s
Press any key to continue.
请原谅我的非技术性解释,非常感谢 这里发生的是堆栈溢出。这是因为函数的每次调用都会创建一个新的堆栈帧,如果堆栈帧太多,堆栈的内存就会耗尽。您可以通过使用迭代而不是递归来修复它 另外,
long
可能无法保存collatz序列为113383
的起始值生成的数字(我在MSVC中没有)。改为使用long
,至少64位大。总而言之,它可能是这样的:
void collatz(long long n)
{
long o;
for (o = 0; n > 1; o++) {
if (n % 2 == 0)
n /= 2;
else
n = n * 3 + 1;
}
printf("%ld\t", o);
return;
}
int main()
{
collatz(113383);
return 0;
}
请注意,我们现在有一个
for
循环,而不是递归。在C标准本身中,递归深度没有限制。您可能会导致堆栈溢出,但堆栈大小在不同的环境中是不同的。我认为Windows有1MB,Linux有8MB。它还取决于函数堆栈帧的大小,而堆栈帧的大小又取决于它有多少变量和类型
在本例中,您有两个long
变量,每个变量可能有8个字节。您还有字符串“%ld\t”
,它是5个字节,可能会在堆栈上结束,但我不确定。除此之外,还有两个指向函数返回地址和上一个堆栈帧的指针的开销,在64位系统上,每个指针都是8字节。因此,函数的堆栈帧大约是32字节左右。也许再多一点。所以在Linux系统上,我猜你的函数会在大约20万的深度崩溃
如果这是一个问题,考虑将函数重写为非递归变量。看看Blaze的答案,了解如何为您的案例做到这一点。正如安德烈在下面评论的那样:
附加说明:您可以在Linux下使用ulimit-s(也可以使用ulimit-s unlimited)增加堆栈大小,在MSVC中,您可以设置/F编译标志以增加程序的堆栈大小。有关MinGW,请参阅post
函数不会为
n==1
返回任何值。当函数到达printf
时,函数不会返回值。也许你应该返回o
而不是打印collatz中的值,并在调用函数中打印结果。0xC00000FD表示堆栈溢出。是的,堆栈大小有限。为了更好地理解functionality@500-InternalServerError谢谢,虽然我的系统相对强大,但是堆栈是静态的吗?这意味着系统之间的音量是否会发生变化?附加说明:在Linux下,您可以使用(也可以是:ulimit-s unlimited
)增加堆栈大小,在MSVC中,您可以设置/compilation标志以增加程序的堆栈大小。关于MinGW,请参阅帖子。回答不错。我对格式做了一些改进。希望你不介意。@Broman一点也不介意!谢谢你的修复。我也很感谢你的回答,它为OP提供了更多的技术见解。