为什么我们不能使用静态变量来实现尾递归?

时间:2013-08-07 05:49:46

标签: c recursion functional-programming tail-recursion static-variables

我正在学习C,所以我正在写一些little exercises in C来练习这门语言。

我有使用功能代码的经验,所以我喜欢递归。我认为使用C静态变量实现尾递归会很棒,因此不需要额外的参数或辅助函数。

使用递归计算阶乘的代码失败:

long long int fact(int n)
{
    static long long int result = -1;

    if(n <= 0) {
        if(result < 0)
            return 1;
        else {
            long long int temp = result;
            result = -1;
            return temp;
        }
    } else {
        result *= n;
        fact(n - 1);
    }
}

然而,出于某种原因,我不能在C中这样做。是否有同样的成语?它只是我的编译器吗?记忆怎么样?

非常感谢。

3 个答案:

答案 0 :(得分:4)

您的代码已损坏,因为它有一个不返回值的控制路径。 This works fine

long long int fact(int n)
{
    static long long int result = 1;

    if(n <= 1) {
        long long int temp = result;
        result = 1;
        return temp;
    } else {
        result *= n;
        return fact(n - 1);
    }
}

GCC does successfully transform the tail recursion to iteration

一般来说,我认为避免使用静态函数进行尾递归的原因仅仅是因为函数失去了重入性。如此多的代码最终必须在多线程环境中运行,因此很难证明在代码中保留函数本地静态“地雷”是合理的。我承认这与技术论点一样多。非静态尾递归代码:

static inline long long int fact_(int n, long long int result)
{
    if(n <= 1) {
        return result;
    } else {
        return fact_(n - 1, result * n);
    }
}

long long int fact(int n)
{
    return fact_(n, 1);
}

如果有更容易写的东西 - 特别是两个版本都是13 LOC - 和compiles just as efficiently to iteration but without needing static data

答案 1 :(得分:1)

您的else块似乎没有明确的返回值。你没有得到编译器警告吗?请确保您正在编译并打开所有警告。

基本上,您需要将return result;添加到else块的末尾,否则您将如何将结果返回给原始调用者?请记住,返回只弹出一个函数调用,当你调用return时,你是一个任意深度,因为你在else块中对fact()进行了所有递归调用。

答案 2 :(得分:1)

int factorial(int n)
{
    static int m = 1;
    m *= n;
    if (n > 1)
        factorial(n - 1);
    return m;
}