求一个数的阶乘的递归函数
Recursive function for finding factorial of a number
我得到 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)
,并且它将是 return 的 4 倍,而不是 5!
.基本上,如果编译器按照那个顺序执行它——它可能会! -- 然后 number
会“过早”递减。
您可能想不到编译器可以这样做。
您可能会想象表达式总是“从左到右解析”。
但是那些想象是不正确的。
(有关评估顺序的更多讨论,另请参阅 。)
我说表达式导致“未定义的行为”,这个表达式就是一个典型的例子。使这个表达式未定义的原因是它里面发生的事情太多了。
表达式的问题
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
所做的那样),我们只是在传递较小的值之前从中减去 1关闭递归调用。
所以现在,我们没有违反规则,我们没有在同一个表达式中使用和修改 number
。
我们只是使用它的值两次,这很好。
有关此类表达式中未定义行为的更多信息(更多!),请参阅 Why are these constructs using pre and post-increment undefined behavior?
如何求一个数的阶乘;
function factorial(n) {
if(n == 0 || n == 1 ) {
return 1;
}else {
return n * factorial(n-1);
}
//return newnum;
}
console.log(factorial(3))
我得到 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)
,并且它将是 return 的 4 倍,而不是 5!
.基本上,如果编译器按照那个顺序执行它——它可能会! -- 然后 number
会“过早”递减。
您可能想不到编译器可以这样做。
您可能会想象表达式总是“从左到右解析”。
但是那些想象是不正确的。
(有关评估顺序的更多讨论,另请参阅
我说表达式导致“未定义的行为”,这个表达式就是一个典型的例子。使这个表达式未定义的原因是它里面发生的事情太多了。
表达式的问题
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
所做的那样),我们只是在传递较小的值之前从中减去 1关闭递归调用。
所以现在,我们没有违反规则,我们没有在同一个表达式中使用和修改 number
。
我们只是使用它的值两次,这很好。
有关此类表达式中未定义行为的更多信息(更多!),请参阅 Why are these constructs using pre and post-increment undefined behavior?
如何求一个数的阶乘;
function factorial(n) {
if(n == 0 || n == 1 ) {
return 1;
}else {
return n * factorial(n-1);
}
//return newnum;
}
console.log(factorial(3))