5.函数的嵌套调用和链式访问
函数的嵌套调用:
从字面意思讲就是一个函数里可以调用另一个函数,举个例子:
函数中是不能定义函数的:
我发现一个问题?
总结:函数可以嵌套调用,但是不能嵌套定义。
函数的链式访问:
把一个函数的返回值作为另外一个函数的参数。
就像链条一样将一个函数与另一个函数连接在一起
举几个例子:
注:printf函数的返回值是打印在屏幕上字符的个数
6.函数的声明和定义
6.1函数的声明
语法展示:
声明一个函数就和声明一个变量类似,如果你是先使用但并未声明函数,编译器就会有提示,所以在使用(调用)函数之前一定要声明;
如下图:
6.2函数的定义
语法展示:
相比于函数的声明,我们不如在main函数前直接定义一个函数
以上是语法展示,接下来展示实际应用:
怎么使用这个函数呢?
有一个小细节:
分为多个文件,而不在同一个文件中的原因是:
1.可以进行模块化开发(分工),效率更高;
2.可以做到代码的隐藏,就是我不想让你看到我的代码;
具体操作(原理我不明白):
目的:我不想让你看到我的代码(源码),但是你能使用代码的功能;
7.函数的递归
7.1什么是递归
1.程序调用自身的编程技巧称为递归( recursion)。
2.只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
3.递归的主要思考方式在于:把大事化小
7.2递归的两个必要条件
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。
举个正确的函数递归例子:
接受一个整型值(无符号),按照顺序打印它的每一位。
例如: 输入:1234,输出 1 2 3 4
分析:
再来一道例子:
编写函数不允许创建临时变量,求字符串的长度。
本质上就是让你写一个strlen函数
题目有一个细节,就是编写函数不允许创建临时变量
分析:
7.3递归与迭代
迭代可理解是非递归的方式解决问题;
举个例子:求n的阶乘。(不考虑溢出)
再来一个例子:
求第n个斐波那契数。(不考虑溢出)
分析:
图中有好多重复的部分:
1. 在使用 fibonacci 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。
2.使用 test函数求10000的阶乘(不考虑结果的正确性),程序会崩溃;
总结:
1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开 销。
4.解决栈溢出这个问题,可以将递归换成迭代;也可以将栈区的临时变量,局部变量转到静态区上,可以一定程度上节省栈区的空间。
函数递归的几个经典题目:
1. 汉诺塔问题
2. 青蛙跳台阶问题