递归函数是否有一些限制?例如:功能需要几层?

时间:2019-05-03 12:10:23

标签: c

制作了一个递归函数,该函数给出给定起始编号的collat​​z序列中有多少个术语,例如:代码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 main()
{
    collatz(13,0);
}

函数按预期运行;但是,对于某些整数,例如“ n = 113383”,某些东西会溢出(我想)并返回:

Process returned -1073741571 (0xC00000FD)   execution time : 4.631 s
Press any key to continue.

不好意思,非常感谢!

2 个答案:

答案 0 :(得分:3)

C标准本身对递归深度没有限制。您可能会导致堆栈溢出,但是在不同的环境中堆栈大小会有所不同。我认为Windows有1MB,Linux有8MB。它还取决于函数的堆栈框架的大小,而堆栈的大小又取决于函数具有多少变量和哪种类型。

在您的情况下,您有两个long变量,每个变量可能是8个字节。您还有一个字符串"%ld\t",它是5个字节,可能会在堆栈上结束,但是我不确定。最重要的是,您有两个指向函数返回地址和前一个堆栈帧的指针的开销,在64位系统上,它们分别为8个字节。因此,函数的堆栈帧大约为32个字节左右。也许更多。因此,在Linux系统上,我猜想您的功能将在大约20万的深度崩溃。

如果这是一个问题,请考虑将函数重写为非递归变量。查看Blaze的答案,以了解如何针对您的案例。正如安德烈(Andreee)在下面的评论:

  

附加说明:您可以在Linux下使用ulimit -s增加堆栈大小(也可以:ulimit -s unlimited),而在MSVC中,可以设置/ F编译标志来增加程序的堆栈大小。对于MinGW,请参阅this帖子。

答案 1 :(得分:2)

这里发生的是堆栈溢出。发生这种情况是因为每次调用该函数都会创建一个新的堆栈帧,并且如果堆栈帧过多,则堆栈的内存将用完。您可以使用迭代而不是递归来解决它。

此外,long可能无法保存collat​​z序列为起始值113383生成的数字(对于MSVC而言,这不是我的意思)。请改用long 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循环而不是递归了。