【C语言】函数的递归

前言

函数的递归是函数的重要部分,全面我们写了一篇关于C语言的自定义函数,相信大家对函数也有了一定的了解,那么这里单独把函数递归拿出来讲是为了讲的更清楚一点,但是如果有讲错的地方也请大佬指正,有不够详细的地方也请大家多多海涵


一、函数递归的介绍

1. 什么是函数的递归?

递的递推的意识,归是归来的意思,所以可以理解为一个函数进行了递推与回归,递归也就是一个函数调用它自己的过程,函数体中调用自己是递推当最后一个被调用的函数结束后往回就是归来,我知道这样讲是有点抽象的,但是后面让我们慢慢理解

2. 递归的好处

  • 代码简化减少重复代码: 递归是函数调用自身来解决问题,代码会相对简洁
  • 问题分解: 递归允许你将复杂问题分解成更小、更易于管理的子问题。这种分解有助于以模块化的方式解决问题。

至于以上的好处我们会在后面的代码中体现


二、函数递归的实现

1. 最简单的函数递归

#include <stdio.h>
int main() {

	main();

	return 0;
}

上面我们在main函数中调用了main函数来实现最简单的递归,但是这个递归是没有停止条件的,所以,它会导致严重我问题:栈溢出
在这里插入图片描述
Stack overflow 栈溢出

2. 函数递归的限制条件

为了避免我们递归出现上面的情况,我们需要给实现递归安置一些限制条件

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

我们举个例子说明一下这两个条件

//使用递归求n的阶乘
#include <stdio.h>

int NFactorial(int n) {
	if (n > 1)
		return n * NFactorial(n - 1);
	return 1;
}

int main() {

	int n = 0;
	printf("请输入n的值:");
	scanf("%d", &n);
	printf("%d 的阶乘为:%d\n", n, NFactorial(n));

	return 0;
}

在这里插入图片描述
上面我们使用递归函数进行了对1~n的阶乘求值,下面我们分析一下递归函数中的两个限制条件
第一函数的结束条件其实是当 n 的值为 1 时,函数递归就会结束
第二函数在调用自身时传入的值是 n-1 ,每次递归调用之后越来越接近 n 的值等于 1 这个限制条件

3. 函数递归的过程图解

为了方便了解,我们可以画出递归展开图,更直观的展示递归的过程
在这里插入图片描述
通过这个图,我们可以更加直观的理解函数递归的过程


三、函数递归与内存空间

在C语言中每一次函数调用,都需要为本次函数调用在内存的栈区,申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。关于函数栈帧的创建与销毁在我的C语言栏目文章中我专门的讲解哦,大家可以去看看!

函数递归在内存中的细节: 函数不返回,函数对应的栈帧空间就一直占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。也就是说函数递归这个过程中函数的栈帧不断创建一直往栈上累加,直到函数达到限制条件,函数的栈帧才会从上往下开始释放。

注: 如果递归的深度太深,栈帧过多的创建则会导致栈溢出


四、End

对于函数递归我们就讲到这里,函数的递归是一个非常巧妙的方法,可以帮助我们把复杂的问题化简为简单的小问题,如上面求n的阶乘,我们要知道5的阶乘,那我们知道4的阶乘后就可以用5乘于4的阶乘得到5的阶乘,而需要知道4的阶乘,我们可以在知道3的阶乘后,用4乘于3的阶乘得到,以此类推。 最后谢谢大家的阅读,希望对大家有帮助!

### C语言中的函数递归及其用法 #### 什么是函数递归? 在C语言中,函数递归是指一个函数在其自身的函数体内部调用了自己的一种编程技术。这种机制使得某些复杂问题可以通过分解成更小的子问题来解决[^2]。 #### 函数递归的基本结构 为了实现有效的递归,通常需要满足以下几个条件: 1. **基准条件(Base Case)**:这是递归停止的地方,防止无限循环导致堆栈溢出。 2. **递推表达式(Recursive Expression)**:通过将大问题逐步缩小到较小规模的问题来进行求解。 下面是一个经典的阶乘计算例子: ```c #include <stdio.h> // 定义递归函数用于计算阶乘 int factorial(int n) { if (n == 0 || n == 1) { // 基准条件 return 1; } else { return n * factorial(n - 1); // 递推表达式 } } int main() { int number; printf("请输入一个正整数以计算其阶乘: "); scanf("%d", &number); if (number >= 0) { printf("%d 的阶乘是 %d\n", number, factorial(number)); } else { printf("输入错误! 阶乘只适用于非负整数。\n"); } return 0; } ``` 在这个例子中,`factorial()` 是一个典型的递归函数。它利用了一个简单的逻辑——任何大于零的自然数 `n` 的阶乘都可以表示为 `n * (n-1)!`,直到达到基本情况即 `n=0 或者 n=1`[^3]。 #### 关于递归的一些注意事项 尽管递归是一种强大的工具,但也存在一些潜在的风险和局限性。例如,在上述无终止条件的情况下不断自我调用最终会导致系统资源耗尽而崩溃的情况: ```c void endlessRecursion() { printf("This will eventually cause a stack overflow.\n"); endlessRecursion(); // 缺乏退出条件 } ``` 此代码片段展示了没有适当基线情况下的危险后果—持续增加的新层压入调用栈直至超出容量限制引发异常中断。 因此,在设计递归算法时务必小心谨慎地设定好边界条件以及考虑性能影响等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值