一、递归函数。
1、什么是递归函数?
递归函数就是在一个自定义函数中,自己调用自己。
例如:
void func()
{
...;
...;
...;
func();
...;
}
int main()
{
func();
}
2、递归函数有什么特点?
特点:递归函数自己调用自己,造成无限递归,没有终止时刻。
以下程序运行之后会导致什么情况? --> 造成栈溢出。
void func()
{
int a; //在内存中连续申请4个字节的空间,使用变量a间接访问。
func();
}
int main()
{
func();
}
结论:递归函数没有一个终止条件,那么就会造成栈溢出,所以一般情况下,我们都会在递归函数中添加一个终止条件。
也就是说,在到达某一个瞬间的时候,就不要再调用自己了。
3、递归函数题型。
题型1: 给程序,求结果。
请问以下的程序运行结果是什么?
void func(int n)
{
if(n > 1)
{
func(n-1);
}
printf("n = %d\n",n);
return;
}
int main()
{
func(100);
return 0;
}
答案:1~100
解题思路:
1)找到终止条件。 n=1
2)列出前面几项与靠近终止条件的几项,观察规律。
3)通过画图,分析函数返回的位置。
题型2: 给规律,写程序。
请写出以下程序的结果:
有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生多少岁,他说比第3个学生大2岁。问第3个学生多少岁,他说比第2个学生大2岁。问第2个学生多少岁,他说比第1个学生大2岁。问第1个学生多少岁,他说是10岁。请问第5个学生多少岁?要求你使用递归函数来完成。
解题思路:
1)找到终止条件 --> get_age(1)就是10岁。
2)找到最终目标与终止条件之间的关系。 get_age(5)与get_age(1)有什么关系?
get_age(5) = get_age(4) + 2
get_age(4) = get_age(3) + 2
get_age(3) = get_age(2) + 2
get_age(2) = get_age(1) + 2
3)根据关系,求出通项公式。
get_age(x) = get_age(x-1) + 2
4)根据关系,代入模板。
int fun(xxx)
{
/* 1. 错误判断 */
/* 2. 终止条件 */
/* 3. 通项公式 */
}
------------------------------------------
#include <stdio.h>
int get_age(int n)
{
int age;
/* 1. 错误判断 */
if(n <= 0)
return -1;
/* 2. 终止条件 */
if(n == 1)
age = 10;
/* 3. 通项公式 */
if(n > 1)
age = get_age(n-1) + 2;
return age;
}
int main()
{
int age = get_age(3);
printf("age = %d\n",age);
return 0;
}
----------------------------------------------
练习1: 有以下程序,假设输入一个10,求结果。 53
int fun(int n)
{
if(n == 1)
{
return -1;
}
else{
return (n + fun(n-1));
}
}
int main()
{
int x;
scanf("%d",&x);
x = fun(x);
printf("x = %d\n",x);
return 0;
}
练习2: 第一天存100元,后面的第一天都比昨天多存10元,请问第312天当天存了多少钱?
1)找到终止条件 fun(1)->100
2)找到终止条件与最终目标之间的关系
fun(312) = fun(311) + 10;
fun(311) = fun(310) + 10;
fun(310) = fun(309) + 10;
.....
fun(3) = fun(2) + 10;
fun(2) = fun(1) + 10;
3)求通项公式
fun(n) = fun(n-1) + 10;
练习3: 将小孩岁数这题的运行内存变化图分析出来。
二、回调函数。
1、什么是回调函数?
先定义好函数A(准备水,喝水的过程),然后将这个函数A作为另外一个函数B(爬山)的参数,在函数B的执行过程(爬山的过程中)中回过头来调用传递进来的参数(喝水),那么函数A就是回调函数了。
2、回调函数基本框架。
int funB(funA)
{
...;
...; -> 函数B的执行过程中
funA; -> 回过头来调用函数A,函数A就称之为回调函数
}
int funA() //先定义好函数A的实现过程
{
/* 水 */
}
int main()
{
funB(funA);
}
区别普通函数的实现。
int funB()
{
/* 爬山 */
...
funA();
}
int funA()
{
/* 喝水 */
}
int main()
{
funB(); //去爬山
return 0;
}
3、回调函数的核心。
先写好你的功能函数,再将这个功能函数作为另外一个函数的参数就可以了。
例题: 从键盘中获取两个数字,求出两个值的和,要求使用回调函数来完成。
1)通过分析,求和功能作为回调函数。
int add_fun(int x,int y) -> add_fun()就是函数A
{
return x + y;
}
2)在main函数中调用一个函数,将回调函数作为该函数的参数,进行求和。
int main(int argc,char *argv[])
{
int a,b,ret;
scanf("%d %d",&a,&b);
ret = my_fun(a,b,add_fun); //实参 --> my_fun()就是函数B
printf("ret = %d\n",ret);
}
3)写函数的实现过程?
int my_fun(int a,int b,int (*p)(int,int)) //形参 //a = a b = b p = add_fun
{
4)在函数内部,只需要将p当做是函数名来处理即可。
int ret;
ret = p(a,b);
return ret;
}
问题一:传递了一个add_fun函数过来,形式参数怎么写?
分析:在C语言中,传递一个函数作为参数,其实就是传递了函数的地址过来,并没有传递整个函数过来,在形式参数中只需要写一个函数指针变量来接住这个地址即可。
问题二:函数指针变量怎么写?
按照以下的步骤来写即可:
1)先写一个* *
2)在*后面加上一个变量的名字,然后使用圆括号括住 (*p)
3)确认你传递的函数是长什么样子的? int add_fun(int x,int y)
4)将第3步的结果的函数名与所有形式参数变量名去掉 int (int ,int )
5)将第2步的结果写在第4步结果的返回值类型与形式参数之间 int (*p)(int ,int )
最终结果: int (*p)(int ,int)
问题三:传递过来的add_fun函数,在my_fun()中如何调用?
传递过来之后,你需要把指针变量名当成函数名来使用即可。
---------------------------回调函数写法-----------------------------------------
#include <stdio.h>
int add_fun(int x,int y) //-> add_fun()就是函数A
{
return x + y;
}
int my_fun(int a,int b,int (*p)(int,int)) //a = a b = b p = add_fun
{
int ret;
ret = p(a,b);
return ret;
}
int main(int argc,char *argv[])
{
int a,b,ret;
scanf("%d %d",&a,&b);
ret = my_fun(a,b,add_fun); // --> my_fun()就是函数B
printf("ret = %d\n",ret);
}
-------------------------------普通函数写法------------------------------------------
#include <stdio.h>
int add_fun(int x,int y) //-> add_fun()就是函数A
{
return x + y;
}
int my_fun(int a,int b)
{
int ret = add_fun(a,b);
return ret;
}
int main(int argc,char *argv[])
{
int a,b,ret;
scanf("%d %d",&a,&b);
ret = my_fun(a,b); // --> my_fun()就是函数B
printf("ret = %d\n",ret);
}
练习3: 连续从键盘中获取4个数字,求出其中的最大值,使用回调函数来完成。
#include <stdio.h>
int get_2_max(int x,int y) //函数A
{
if(x > y)
return x;
else
return y;
}
int get_4_max(int x,int y,int z,int k,int (*p)(int,int))
{
int m;
m = p(x,y);
m = p(m,z);
m = p(m,k);
return m;
}
int main(int argc,char *argv[])
{
int a,b,c,d;
scanf("%d %d %d %d",&a,&b,&c,&d);
int ret = get_4_max(a,b,c,d,get_2_max); //把函数A作为另外一个函数B的参数
printf("ret = %d\n",ret);
return 0;
}
三、内联函数。
1、什么是内联函数?
在程序中调用函数,是需要花费一定的时间来保护现场的,在函数返回时,又需要花费一定的时间来恢复现场,这样就会导致运行速度降低。
但是使用内联函数之后,就既可以使用函数的封装,又不需要花费时间来保护现场与恢复现场。
例子1:
int main(int argc,char *argv[])
{
printf("helloworld!\n");
printf("helloworld!\n");
printf("helloworld!\n");
return 0;
}
例子2:
void func()
{
printf("helloworld!\n");
}
int main(int argc,char *argv[])
{
---> 保护现场
func();
---> 恢复现场
---> 保护现场
func();
---> 恢复现场
---> 保护现场
func();
---> 恢复现场
return 0;
}
2、如何实现内联函数呢?
1)先完成代码。
void func()
{
printf("helloworld!\n");
}
int main(int argc,char *argv[])
{
func();
func();
func();
return 0;
}
2)将需要写成内联函数的函数接口前面加上一个关键词:inline
#include <stdio.h>
inline void func()
{
printf("helloworld!\n");
}
int main(int argc,char *argv[])
{
func();
func();
func();
return 0;
}
3)创建一个.h文件,并命名为my_head.h
4)将这个内联函数剪切到my_head.h中。
---------------test.c---------------
#include <stdio.h>
int main(int argc,char *argv[])
{
func();
func();
func();
return 0;
}
---------------my_head.h-------------
inline void func()
{
printf("helloworld!\n");
}
-------------------------------------
5)在.c文件中,包含我们写得头文件。 #include "my_head.h"
---------------test.c---------------
#include <stdio.h>
#include "my_head.h"
int main(int argc,char *argv[])
{
func();
func();
func();
return 0;
}
---------------my_head.h-------------
inline void func()
{
printf("helloworld!\n");
}
-------------------------------------
6)在.c文件中,再声明一次函数即可。
---------------test.c---------------
#include <stdio.h>
#include "my_head.h"
void fun();
int main(int argc,char *argv[])
{
func();
func();
func();
return 0;
}
---------------my_head.h-------------
inline void func()
{
printf("helloworld!\n");
}
-------------------------------------
练习4: 自己写一份代码,实现内联函数。