标签:
例1:
#include <stdio.h>
/**
函数功能:用递归实现位运算加法
*/
int Add_Recursion(int a,int b)
{
int carry_num = 0, add_num = 0;
if (b == 0)
{
return a;
}
else
{
add_num = a^b;
carry_num = (a&b)<<1;
Add_Recursion(add_num, carry_num);
}
}
int main()
{
int num = Add_Recursion(1, 1);
printf("%d\n",num);
getchar();
}
例2:
#include <stdio.h>
int changestack()
{
return 3;
}
/**
函数功能:用递归实现位运算加法
*/
int Add_Recursion(int a,int b)
{
int carry_num = 0, add_num = 0;
if (b == 0)
{
return a;
}
else
{
add_num = a^b;
carry_num = (a&b)<<1;
Add_Recursion(add_num, carry_num);
changestack();
}
}
int main()
{
int num = Add_Recursion(1, 1);
printf("%d\n",num);
getchar();
}
else
{
add_num = a^b;
carry_num = (a&b)<<1;
return Add_Recursion(add_num, carry_num);
changestack();
}
——————–图三 例二函数的递归分析—————————
我们分析上边代码的运行过程,首先在main函数中调用Add_Recursion(1,1),本意就是计算1+1的值,并且将函数返回值传递给printf打印出来。
在递归调用Add_Recursion函数(简称add)计算1+1时,前两次递归调用由于不满足递归出口条件(进位加数carry_num为0),会跳入else分支进行递归调用。直到第三次递归调用时由于carry_num为0,这时返回了累加结果。
我们在下图中可以看到main函数中将changestack()的返回值给num赋值的具体过程,也就是将eax的值返回给num的所在的内存地址。
——————————图五 函数返回值的“弹栈”细则——————————-
这样一切就有了解释。
——————-图六 例题一为什么会碰巧正确的递归分析—————
——————————-图七 用内联汇编解读C语言的return本质—————————–
我们在递归函数Add_Recursion的后边加了一条汇编代码,让函数结束时改变eax的值。可以看到,主函数中,将函数返回值误认为了我们在汇编语言中设定的3.打印出了1+1=3这种谬论。
实际上,我们在编译例题中的程序在编译时C编译器会提出警告
warning C4715: “Add_Recursion”: 不是所有的控件路径都返回值
有返回值的函数,不是所有的支路都会进行返回值,如果大家把博客中的程序在更加严格的C++编译器上编译会报错。
这只是一个很简单的案例,也许我们会运气好实现函数的功能,但是在进行复杂情况的树状甚至图状递归中,如果不确定自己是否一定能得到最终结果,请务必将每一种情况都return返回值,这样来避免程序意外出错。C语言的灵活性应该给我们造福,而不应该给我们的程序提供不稳定的因素。
C语言中递归什么时候可以省略return引发的思考:通过内联汇编解读C语言函数return的本质
标签:
原文地址:http://blog.csdn.net/u013926582/article/details/51175645