程序调用自身的编程技巧被称为递归。举个例子:
int main()
{
printf("hehe\n");
main();
return 0;
}
比如这种,自己调用自己后每次都打印一个hehe。
递归的核心思考方式在于:大事化小。
做个练习:接收一个整型值(无符号),按照顺序打印它的每一位。例如:输入1234,输出1 2 3 4.
没有递归的策略是做一个循环把这个数先除10再模10然后存一下进入下一个循环判断剩余数是除10是否为0。
1234%10=4
1234/10=123%10=3
123/10=12%10=2
12/10=1%10=1
1/10=0
用递归的方法:
void print(unsigned int n)//返回值类型设置为void因为不需要返回,我直接用print打印到屏幕即可。参数类型跟main函数里的num一样。
{
if (n > 9)
{
print(n / 10);
}
printf("%d\n", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%u", &num);//比如1234
//递归-函数自己调用自己
print(num);//print函数打印参数部分数字的每一位。
return 0;
见print函数里,我们需要依次执行1234%10 123%10 12%10 1%10并且依次打印。所以函数里要做的是把参数n模10打印然后除以10递归到下一个print函数里.执行一下这个代码试试:
递归两个必要条件:
- 递归必须存在限制条件,当满足这个限制条件,递归不再继续。
- 每次递归越来越接近这个限制条件。
这两个是必要条件,不是充分,如下代码:
void test(int n)
{
if (n < 10000)
{
test(n+1);
}
}
int main()
{
test(1);
return 0;
}
执行后报错,提示如下。
解释栈溢出(stack overflow):
内存分为
- 栈区:局部变量、函数形参
- 堆区:动态内存分配
- 静态区:全局变量、静态变量
每一个函数调用都需要在栈区分配一块空间,比如调用main函数,分配一块给main函数,这块空间较main函数栈帧空间。当函数递归时候,每一次test都要调用空间,比如test1000,test999每一个调用的时候上一个函数都没有结束所以上一次函数的空间还没有清除,如果递归太深,会导致内存的栈区被用光,产生上述的情况栈溢出。
所以写递归代码的时候:
- 不能死递归,有跳出条件,每次递归逼近跳出条件。
- 递归层次不能太深
网站:StackOverflow:程序员的知乎