百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

C语言函数递归调用理解

off999 2024-12-08 17:27 13 浏览 0 评论

函数除了在其他地方被调用之外,也可以自己调用自己(好家伙,套娃是吧),这种玩法我们称为递归。

#include <stdio.h>

void test(){
    printf("Hello World!\n");
    //函数自己在调用自己,这样的话下一轮又会进入到这个函数中
    test();   
}

int main() {
    test();
}

我们可以尝试运行一下上面的程序,会发现程序直接无限打印Hello World!这个字符串,这是因为函数自己在调用自己,不断地重复进入到这个函数,理论情况下,它将永远都不会结束,而是无限地执行这个函数的内容。

但是到最后我们的程序还是终止了,这是因为函数调用有最大的深度限制,因为计算机不可能放任函数无限地进行下去。

重点理解函数调用栈

#include <stdio.h>
int test2(){
    printf("函数调用栈 test2\n");
    return 2;
}
int test1(){
    int num = test2();   //main -> test -> test2
    printf("test2执行完了:%d\n", num);
    printf("函数调用栈 test1\n");
    return 1;
}
int main() {
    int num = test1();
    printf("test1执行完了:%d\n", num);
    printf("函数调用栈 main\n");
    return 0;
}

其实我们可以很轻易地看出整个调用关系,首先是从main函数进入,然后调用test函数,在test函数中又调用了test2函数,此时我们就需要等待test2函数执行完毕,test才能继续,而main则需要等待test执行完毕才能继续。而实际上这个过程是由函数调用栈在控制的!

而当 test2 函数执行完毕后,每个栈帧又依次从栈中出去 栈的规律:先进后出,后进先出!

当所有的栈全部出去之后,程序结束!

所以这也就不难解释为什么无限递归会导致程序出现错误,因为栈的空间有限,而函数又一直在进行自我调用,所以会导致不断地有新的栈帧进入,最后塞满整个栈的空间,就爆炸了,这种问题我们称为栈溢出(Stack Overflow)

按照规范使用递归操作,是非常方便的,比如我们现在需要求某个数的阶乘:

#include <stdio.h>

int test(int n);

int main() {
    printf("%d", test(3));
}

int test(int n) {
    //因为不能无限制递归下去,所以我们这里添加一个结束条件,在n = 1时返回
    if (n == 1) return 1;
    //每次都让n乘以其下一级的计算结果,下一级就是n-1了
    int result = test(n - 1) * n;
    return result;
}

通过给递归函数调用适当的添加结束条件,就不会出现死循环,程序看起来比较简介,详细执行过程如下:

递归函数看起来就像是一个先走到底部,然后拿到问题的钥匙后逐步返回的一个过程,并在返回的途中不断进行计算最后得到结果!所以,合理地使用递归反而是一件很有意思的事情。

递归输出详细图解

#include <stdio.h>
void test(int count);

int main() {
    // 标准的输入输出不需要缓存,直接输出
    setbuf(stdout, NULL);
    test(4);
    return 0;
}

void test(int count) {
    if (count == 1) {
        return;
    }
    printf("第一行打印数据【%d】\n", count);
    printf("第二行打印数据【%d】\n", count);
    test(count - 1);
    printf("第三行打印数据【%d】\n", count);
    printf("第四行打印数据【%d】\n", count);
}


【线下辅导】本人从事IT行业6年,科班出生,毕业于西安邮电大学软件工程专业。有扎实的编程基础,C语言 Java语言 Python语言,数据结构,Linux操作系统,计算机网络都比较擅长,可以带大学生入门到实践,打好坚实的编程基础!

联系方式(微信同号)15091672137

相关推荐

独家 | 5 个Python高级特性让你在不知不觉中成为Python高手

你已经使用Python编程了一段时间,编写脚本并解决各种问题。是你的水平出色吗?你可能只是在不知不觉中利用了Python的高级特性。从闭包(closure)到上下文管理器(contextmana...

Python装饰器

Python装饰器是一种用于修改函数或类的行为的特殊语法。它们允许在不修改原始代码的情况下,通过将函数或类作为参数传递给另一个函数来添加额外的功能。装饰器本质上是一个函数,它接受一个函数作为参数,并返...

中高阶Python常规用法--上下文管理器

Python以简单性和通用性著称,是一种深受全球开发人员喜爱的编程语言。它提供了大量的特性和功能,使编码成为一种愉快的体验。在这些功能中,一个经常被新手忽视的强大工具是上下文管理器。上下文管理器是高...

Python小案例67- 装饰器

Python装饰器是一种用于修改函数或类的行为的特殊语法。它们允许在不修改原始代码的情况下,通过将函数或类作为参数传递给另一个函数来添加额外的功能。装饰器本质上是一个函数,它接受一个函数作为参数,并返...

python常用的语法糖

概念Python的语法糖(SyntacticSugar)是指那些让代码更简洁、更易读的语法特性,它们本质上并不会增加新功能,但能让开发者更高效地编写代码。推导式写法推导式是Python最经典的...

python - 常用的装饰器 decorator 有哪些?

python编程中使用装饰器(decorator)工具,可以使代码更简洁清晰,提高代码的重用性,还可以为代码维护提供方便。对于python初学者来说,根据装饰器(decorator)的字面意思并不...

python数据缓存怎么搞 ?推荐一个三方包供你参考,非常简单好用。

1.数据缓存说明数据缓存可以说也是项目开发中比不可少的一个工具,像我们测试的系统中,你都会见到像Redis一样的数据缓存库。使用缓存数据库的好处不言而喻,那就是效率高,简单数据直接放在缓存中...

用于时间序列数据的Graphite监视工具

结合第三方工具,Graphite为IT性能监控提供了许多好处。本文介绍其核心组件,包括Carbon、Whisper以及安装的基本准则。Graphite监视工具可实时或按需,大规模地绘制来自多个来源的时...

Python3+pygame实现的坦克大战

一、显示效果二、代码1.说明几乎所有pygame游戏,基本都遵循一定的开发流程,大体如下:初始化pygame创建窗口while循环检测以及处理事件(鼠标点击、按键等)更新UI界面2.代码创建一个m...

Python之鸭子类型:一次搞懂with与上下文装饰器

引言在鸭子类型的理念的基础之上,从关注类型,转变到关注特性和行为。结合Python中的魔法函数的体系,我们可以将自定义的类型,像内置类型一样被使用。今天这篇文章中,接着该话题,继续聊一下with语法块...

Python必会的50个代码操作

学习Python时,掌握一些常用的程序操作非常重要。以下是50个Python必会的程序操作,主要包括基础语法、数据结构、函数和文件操作等。1.HelloWorldprint("Hello,...

一文掌握Python 中的同步和异步

同步代码(Sync)同步就像在一个流水线上工作,每个任务都等待前一个任务完成。示例:机器A切割钢板→完成后,机器B钻孔→完成后,机器C上色。在Python中,同步代码看起来像这样:im...

python 标注模块timeit: 测试函数的运行时间

在Python中,可以使用内置的timeit模块来测试函数的运行时间。timeit模块提供了一个简单的接口来测量小段代码的执行时间。以下是使用timeit测试函数运行时间的一般步骤:导入...

Python带你找回童年的万花尺

还记得小时候的万花尺吧?这么画:一点也不费脑筋,就可以出来这么多丰富多彩的复杂几何图形。具体而言,可以用万花尺玩具(如图2-1所示)来绘制数学曲线。这种玩具由两个不同尺寸的塑料齿轮组成,一大一小。小的...

Python 时间模块深度解析:从基础到高级的全面指南

直接上干货一、时间模块核心类介绍序号类名说明1datetime.datetime表示一个具体的日期和时间,结合了日期和时间的信息。2datetime.date表示一个具体的日期。3datetime.t...

取消回复欢迎 发表评论: