微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用于查找数字阶乘的递归函数

如何解决用于查找数字阶乘的递归函数

我得到 24 的输出,这是 4 的阶乘,但我应该得到 5 阶乘的输出,即 120

#include <stdio.h>
int factorial(int number){
    if(number==1){
        return number;
    }
    return number*factorial(--number);
}
int main(){
    int a=factorial(5);
    printf("%d",a);
}

解决方法

您的程序存在未定义行为

在第一次调用 factorial(5) 时,你有

return number * factorial(--number);

你想象这会计算

       5      * factorial(4);

但这并不能保证!
如果编译器以不同的顺序查看它会怎样?
如果先在右侧工作会怎样?
如果它首先执行相当于:

temporary_result = factorial(--number);

然后做乘法:

return number * temporary_result;

如果编译器按照这个顺序执行,那么 temporary_result 将是 factorial(4),并且它会返回 4 倍,这不会是 5!。基本上,如果编译器按照这个顺序来做——它可能会! -- 然后 number 会“过早”递减。

您可能没有想到编译器可以这样做。
您可能已经想象过表达式总是“从左到右解析”。
但那些想象是不正确的。
(另请参阅 this answer 以了解有关评估顺序的更多讨论。)

我说表达式会导致“未定义行为”,这个表达式就是一个经典的例子。使这个表达式未定义的原因是它内部发生的事情有点太多了。

表达的问题

return number * factorial(--number);

是变量 number 在其中使用了它的值,同样的变量 number 也在其中被修改。这种模式基本上是毒药。

让我们把出现 number 的两个地方标记出来,这样我们就可以很清楚地谈论它们:

return number * factorial(--number);
       /* A */             /* B */

在 A 点,我们取变量 number 的值。
在 B 点,我们修改变量 number 的值。
但问题是,在 A 点,我们得到的是 number 的“旧”值还是“新”值?
我们是在 B 点修改之前还是之后得到的?

正如我已经说过的,答案是:我们不知道。 C 中没有规则可以告诉我们。

同样,您可能认为有关于从左到右求值的规则,但实际上并没有。因为没有规则说明应该如何解析这样的表达式,所以编译器可以做任何它想做的事情。它可以以“正确”的方式或“错误”的方式解析它,或者它可以做一些更奇怪和意想不到的事情。 (而且,实际上,首先没有“正确”或“错误”的方式来解析像这样的未定义表达式。)

解决这个问题的办法是:不要那样做!
不要编写同时使用和修改一个变量(如 number)的表达式。
在这种情况下,正如您已经发现的那样,有一个简单的解决方法:

return number * factorial(number - 1);

现在,我们实际上并没有尝试修改变量 number 的值(如表达式 --number 所做的那样),我们只是在将较小的值传递给递归调用。 所以现在,我们没有违反规则,我们没有在同一个表达式中使用和修改 number。 我们只是两次使用它的值,这很好。

有关此类表达式中未定义行为主题的更多(更多!),请参阅 Why are these constructs using pre and post-increment undefined behavior?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。