首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言】函数递归从入门到精通(手把手带练)

【C语言】函数递归从入门到精通(手把手带练)

作者头像
用户11987028
发布2026-01-15 14:01:23
发布2026-01-15 14:01:23
850
举报

-

在这里插入图片描述
在这里插入图片描述

🎬 个人主页秦苒&专栏传送门:《C语言

🍀指尖燃热血,代码铸锋芒;以信仰破局,向顶峰生长


🎬秦苒&的简介:

在这里插入图片描述
在这里插入图片描述

提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是递归

递归是解决问题的方法,递归就是函数自己调用自己。(说句题外话,自己跟自己玩,他会孤独吗?) 下面我给大家分享一个最简单的递归代码,让大家一起感受一下他的乐趣!

代码语言:javascript
复制
 #include <stdio.h>
 int main()
 {
 printf("943943jqj\n");
 main();//main在函数中又调用了 
return 0;
 }

上面的递归只是为了演示递归的基本形式,不是为了解决问题,代码最终会陷入是死递归,从而导致栈溢出。 什么是栈溢出咩? 栈溢出(Stack Overflow)是C语言等底层语言中最常见的内存错误之一

核心是: 程序使用的栈内存超出了系统分配的上限,导致内存越界、程序崩溃

1.1递归的思想

把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解,直到问题不能再被分割,递归就结束了。 递归中的递就是递推的意思,归就是回归的意思。

接下来苒苒带着大家慢慢来体会⌯>ᴗ0⌯

1.2递归的限制条件

递归在书写的时候,有2个必要条件: • 递归存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。 • 每次递归调⽤之后越来越接近这个限制条件。(其实我觉得很像y=1/x函数,它的图像越来越接近坐标轴)

在下面的例子中,我们逐步体会这2个限制条件 ˵>𖥦<˵

二.递归的实例

1.2.1求n的阶乘

计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘 相信大家对 n!= n∗(n−1)!这个阶乘公式是不陌生的ᗜωᗜ

陌生的话我悄悄跟你举个栗子 5! = 5x4x3x2x1 4! = 4x3x2x1 ∴5! = 5*4! 这样的思路就是把⼀个较⼤的问题,转换为⼀个与原问题相似,但规模较⼩的问题来求解的。 当n==0 的时候,n的阶乘是1,其余n的阶乘都是可以通过公式计算。 n的阶乘的递归公式如下:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
#include <stdio.h>
int Fact(int n)
{
	if (n == 0)
		return 1;
	else
 
		return n * Fact(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fact(n);
	printf("%d\n", ret);
	return 0;
}

这里苒苒给大家配一张图,以便大家更好“食用”˶⩌ᜊ⩌˶

在这里插入图片描述
在这里插入图片描述

运行结果(这里不考虑n太大的情况,n太大存在溢出):

在这里插入图片描述
在这里插入图片描述
1.2.2顺序打印⼀个整数的每⼀位

输⼊⼀个整数m,按照顺序打印整数的每⼀位。

代码语言:javascript
复制
#include<stdio.h>
void Print(int n)//1234
{
	if (n > 9)
	{
		Print(n / 10);//123
	}
	printf("%d ", n % 10);
}
int main()
{
	int n = 0;
	scanf("%d",&n);
	Print(n);
	return 0;
}

这里苒苒依旧给大家配一张图,方便理解,大家放心“食用”˶⩌ᜊ⩌˶

在这里插入图片描述
在这里插入图片描述

这个是运行结果 ૮・ᴥ - ა

在这里插入图片描述
在这里插入图片描述

三.递归与迭代

递归是⼀种很好的编程技巧,但是和很多技巧⼀样,也是可能被误⽤的,就像举例1⼀样,看到推导的公式,很容易就被写成递归的形式:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
int Fact(int n)
 {
 if(n==0)
 return 1;
 else
 return n*Fact(n-1);
 }

Fact函数是可以产⽣正确的结果,但是在递归函数调⽤的过程中涉及⼀些运⾏时的开销。

我们用这段代码理解

代码语言:javascript
复制
#include<stdio.h>
void Print(int n)//1234
{
	if (n > 9)
	{
		Print(n / 10);//123
	}
	printf("%d ", n % 10);
}
int main()
{
	int n = 0;
	scanf("%d",&n);
	Print(n);
	return 0;
}

他是如何被储存的呢 •︡ᯅ•︠

在C语言中每⼀次函数调用,都需要为本次函数调⽤在内存的栈区,申请⼀块内存空间来保存函数调。 用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。

在这里插入图片描述
在这里插入图片描述

函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调⽤的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。

所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stackoverflow)的问题奥!

如果不想使⽤递归,就得想其他的办法,通常就是迭代的方式(通常就是循环的方式) 例如:计算n的阶乘,也是可以产生1~n的数字累计乘在⼀起的 迭代:

代码语言:javascript
复制
 int Fact(int n)
 {
 int i = 0;
 int ret = 1;
 for(i=1; i<=n; i++)
 {
 ret *= i;
 }
 return ret;
 }

递归:

代码语言:javascript
复制
 int Fact(int n)
 {
 if(n==0)
 return 1;
 else
 return n*Fact(n-1);
 }

上述代码是能够完成任务,并且效率是比递归的方式更好的 >𖥦<੭

我们看到的许多问题是以递归的形式进行解释的,这只是因为它⽐⾮递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高。

当一个问题非常复杂,难以使用迭代的方式实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。


总结

作为C语言学习路上的重要知识点,函数递归曾让我反复踩坑、陷入懵圈。本文记录了我学习递归的完整过程,从最初对递归执行流程的困惑,到逐步拆解逻辑、理解栈帧与递归的关联,再到掌握避坑技巧、适配竞赛真题的实操经验。希望这份真实的学习笔记,能帮和我一样的编程新手,少走弯路、快速入门递归,也愿我们在编程学习中,既能攻克硬核知识点,也能沉淀下属于自己的思考与收获。

结尾

勇敢的寻宝者啊,这次旅途你挖掘到多少宝藏呢,苒苒很期待下次与您相遇!

结语:希望对寻找C语言相关内容的寻宝者有所帮助,不要忘记给博主“一键三连”哦!你的每一次鼓励都为我提供 了前行的动力!

小喵很期待与你再次寻宝奥 ᰔᩚ/•᷅•᷄\୭

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是递归
    • 1.1递归的思想
    • 1.2递归的限制条件
  • 二.递归的实例
    • 1.2.1求n的阶乘
    • 1.2.2顺序打印⼀个整数的每⼀位
  • 三.递归与迭代
  • 总结
  • 结尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档