一、回调函数

什么是回到函数?我们直接通过例子来理解什么是回调函数

文件:a.c

#include <stddef.h>
int (*g_funp)() = NULL;

int fun(int (*funp)())
{
    funp(100);
    g_funp = funp; // g_funp 是全局变量,赋值后其它地方也可以调用
}

文件:b.c

#include <stdio.h>
extern int fun( int (*funp()) );

static int fun1(int a)
{
    printf("%d\n", a);
}

int main()
{
    fun(fun1);

    return 0;
}

由于b.c中的fun1static的,所以在a.c中无法直接调用fun1
所以需要将fun1的函数指针传递给a.cfun,然后再回调fun1函数,fun1函数其实就是回调函数

为了让a.c中的其它函数也能回调fun1,我们可以将函数指针保存到全局变量中

其实我们还可以使用结构体来对函数指针进行封装,然后将结构体传递给对方,
对方从结构体中取出函数指针后,再来回调

后面章节介绍使用结构体来模拟面向对象思想时,会讲到这种发方式


二、函数指针数组

例子:

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int mul(int a, int b)
{
    return a * b;
}

int div(int a, int b)
{
    return a / b;
}

int squ(int a)
{
    return a*a;
}

int main(void)
{
    int  i = 0, ret = 0;
    int da1= 0, da2 = 0;

    //函数参数不一致,所以不要指定任何形参
    int (*funp[5])() = {add, sub, mul, div, squ};

    while(1)
    {
        printf("0. add\n");
        printf("1. sub\n");
        printf("2. mul\n");
        printf("3. div\n");
        printf("4. square\n"); //平方
        printf("select\n");

        scanf("%d", &i);

        if(i == 4)
        {
            printf("input data1\n");
            scanf("%d", &da1);

            ret = funp[i](da1);  //通过函数指针,调用对应函数
        }
        else
        {
            printf("input data1, data2\n");
            scanf("%d %d", &da1, &da2);

            ret = funp[i](da1, da2);
        }

        printf("ret = %d\n", ret);
    }

    return 0;
}

其实可以将例子中ret = funp[i](da1, da2)ret = funp[i](da1)这句话,改为如下方式

switch(i)
{
    case 0:
        ret = add(da1, da2);
        break;
    case 1:
        ret = sub(da1, da2);
        break;
    case 2:
        ret = mul(da1, da2);
        break;
    case 3:
        ret = div(da1, da2);
        break;
    case 4: 
        ret = squ(da1);
        break;
}

通过对比可以发现,使用“函数指针数组”比switch更简洁,
所以如果能够用好“函数指针数组”的话,可以让我们代码变的更加优美和高效