C允许一个函数调用其自身,这种调用过程被称为递归(recursion)
使用递归的风险:如果程序中没有设定可以终止递归的条件检测,会无限制地执行递归调用
所以涉及递归的程序需要谨慎设计
递归一般可以替代循环语句使用:有些需求使用循环语句更好;另一些需求使用递归更合适
整体上,递归方法虽然可以使程序结构优美,但其执行效率往往没有循环语句高
一、递归的使用
示例代码:使用递归实现图案显示
#include <stdio.h>
void symbol_print(int num);
int main(void)
{
symbol_print(1);
return 0;
}
void symbol_print(int num)
{
int i;
for(i = 0; i < num; i++)
{
printf("*");
}
printf("\n");
if(num < 10)
{
symbol_print(num + 1);
}
for(i = 0; i < num; i++)
{
printf("*");
}
printf("\n");
}
运行结果:
同样的功能也可以使用for循环实现(不适用递归):
#include <stdio.h>
void symbol_print(num);
int main(void)
{
int i;
for(i = 0; i <= 10; i++)
{
symbol_print(i);
}
for(i = 10; i >= 0; i--)
{
symbol_print(i);
}
return 0;
}
void symbol_print(int num)
{
int i;
for(i = 0; i < num; i++)
{
printf("*");
}
printf("\n");
}
二、递归的基本原理
1)每一级的函数调用都有自己的变量
2)每一次函数调用都会有一次返回,当程序流执行到某一级递归的结尾处时,会转移到前一级递归继续执行,通过递归的每一级逐步返回
3)递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序
4)递归函数中,位于递归调用后的语句的执行顺序和各级被调用函数的执行顺序相反
5)虽然每一级递归都有自己的变量,但是函数代码并不会得到复制
6)递归函数中必须包含可以终止递归调用的语句
三、尾递归
尾递归:把递归调用语句放在函数结尾,即恰好在return语句之前,这是最简单的递归形式
递归调用出现在函数尾部,其作用相当于一条循环语句
当递归和循环都可以实现某功能时,选择循环更好一点
四、递归的优缺点
优点:
为某些编程问题提供最简单的解决方案,可以写出简洁的代码
缺点:
1)某些场景下递归算法太占用计算机内存资源
2)程序不易阅读和维护
注意:使用递归时必须特别小心,避免不当的使用导致系统瘫痪
一个程序中的每个C函数和其他函数之间是平等关系,每一个函数都可以调用其他任何函数或被其他任何函数调用
虽然main函数是一个有特殊性的函数(计算机总是从main函数中的第一句开始执行整个程序),但是也可以被其自身递归调用或被其他函数调用,虽然显示当中极少这么做