【C语言】剖析函数递归(1)

©作者:凡人编程传
©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

在这里插入图片描述

前言

这一节我们学习函数递归基础知识(下一节开始深入),这几节的内容可谓是函数这个章节最重要的内容,甚至递归在后期的数据结构和算法中都用得到,所以务必好好掌握。好了,咱们直接进入主题.

什么是函数递归?

程序(函数)自己调用自己的编程技巧就叫做递归。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,他通常把一个复杂庞大的问题层层转换为一个与原问题相似的规模较小的问题。递归的主要思考方式在于:把大事化小。

递归的两个必要条件

  1. 递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。
  2. 每次递归调用之后越来越接近这个限制条件。

函数递归实例

例一

我们先来看一下,最简单的递归代码。

#include<stdio.h>
int main()
{
	printf("hehe\n");
	main();		//函数自己调用自己,也就是递归 
	return 0;
}

运行结果:
在这里插入图片描述
可以看到,本以为是死循环打印hehe,最后却报错了。我们不妨调试一下是哪里出了问题.

在这里插入图片描述
调试时,程序却直接崩溃了,可见问题之大。这里他报告的错误是stackoverflow(也就是栈溢出),至于什么是栈溢出,为什么会栈溢出?在这个例子中先卖个关子,放在下一个例子解释。

通过这个例子可知道,我们可以看一下我们的递归代码,是直接调用main()函数的,并没有什么限制条件(也就是函数递归必须满足的两个条件),可以知道,只要我们没有满足递归的两个必要条件,也就会导致死递归,从而导致栈溢出。

例二

题目:接收一个整形值(无符号),按照顺序打印他的每一位,例如输入1234,输出:1 2 3 4

分析:由题意可知,是让我们输入一个无符号整数,然后分别输入它的每一位。这里当然循环结合数组也可以解决,但是我们今天的主角是递归,就要用递归来解决。首先,递归的主要思考方式是把大问题化为一个个相似的小问题,那么我们一下子打印4个数。可不可以拆分一位一位打印呢?因为我们要一位位打印出来,所以每次打印一位取一位打印就行了,但是又因为我们要正序打印(从1开始),所以咱们要从1开始打印,问题来了咋从1开始打印呢?咱们现在是4位数,但是我们可以一直1234/10,除到商1,然后再开始打印!这时候咱的递归条件就出来了,就是(假设1234为n) n>9(这个n>9的意思是为2位数及以上的数),然后每次递归越来越接近不满足这个条件,知道这个n<=9时,也就是n==1时开始打印。

我知道上面说了一大堆肯定你还是不懂,没关系直接看下面代码和我配的图解就能看懂了!

代码如下:

#include<stdio.h>
void print(int k)
{
	if (k > 9)
	{
		print(k / 10);
	}
	printf("%d ", k % 10);
}
int main()
{
	int n;
	scanf("%d", &n);		//输入1234
	print(n);	//递归函数
	return 0;
}

运行结果:
在这里插入图片描述
来,不懂的同学看这张图.
在这里插入图片描述

例三(栈溢出原因)

我们上面说了,函数递归必须要满足两个条件,一是有限制条件,二是每次递归都接近这个条件。如果没有这个条件一定会栈溢出,那么是不是有这两个条件就不栈溢出了呢?

看代码:

#include<stdio.h>
void test(int i)
{
	if(i<10000)
	{
		test(i+1);		
	}
}
int main()
{
	test(1);
	return 0;
}

可以看到递归的限制条件是i<10000,且每次递归时候都i+1,越来越接近这个条件.

运行结果:
在这里插入图片描述
可以看到,即使有这两个必要条件,也是会栈溢出的。那么是为什么呢?

我们先来介绍一下内存布局:
在这里插入图片描述

而每一次的函数调用,都会在栈区上开辟一块内存空间,而这里的test函数递归条件是i<10000,每次递归是i+1,相当于要递归10000-1次,那么每次都要调用这个递归的函数,栈区的内存空间是有限的,所以最后这个代码的结果是栈溢出.

如图所示
在这里插入图片描述
所以,我们如果只保证了两个必要条件还不够,还要保证每次递归的层次不要很深,防止内存空间耗尽。

结言

好了,这一节的内容就是这些,希望对你有收获,我们下一节更精彩!下一节见!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值