第四篇,C语言中的递归函数,回调函数和内联函数详细说明。

一、递归函数。
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: 自己写一份代码,实现内联函数。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖爱Kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值