c语言函数指针与回调函数

目录

一、指针

1、指针

2、野指针与空指针

3、指针的算术运算

4、指针数组:(多个地址)由指针变量组成的数组。

5、多级指针:C 允许指向指针的指针。

6、传递指针给函数:通过引用或地址传递参数,使传递的参数在调用函数中被改变。

7、从函数返回指针(地址)

二、函数指针

1、声明

2、定义

3、调用:可直接用指针调用。

三、回调函数


一、指针

1、指针

指针:指向(/存储)其他变量的地址,该变量的数据类型需与指针的数据类型保持一致。

image-20240312105002379

等价于:

int *p = &var_runoob;

2、野指针与空指针

野指针:没有为指针附地址,此时指针任意指向一个地址,不利于程序安全。

空指针:指针附NULL,地址为0x0。可用于if判断。

注:free()内存后指针赋 NULL。

3、指针的算术运算

对指针进行四种算术运算:++、--、+、- ;指向下一个元素的存储单元,跳跃的字节数取决于所指向变量数据类型长度。

例:

int a[5];

int *p;

p = a;

则*p = a[0], *(p+1) = a[1]

4、指针数组:(多个地址)由指针变量组成的数组。

声明:[]的优先级高于*,因此先是数组,后为指针数组。

const char *names[] = {
                   "Zara Ali",
                   "Hina Ali",
                   "Nuha Ali",
                   "Sara Ali",
};
int i = 0;
for ( i = 0; i < MAX; i++)
{
   printf("Value of names[%d] = %s\n", i, names[i] );//字符型指针数组不用*names[i]
}

区分于数组指针:(一个地址),该指针指向数组,但指向的数组占多少个字节不确定,长度固定(32 位系统下占 4 个字节)。

5、多级指针:C 允许指向指针的指针。

二级指针存一级指针的地址,即二级指针指向一级指针。

三级指针存二级指针的地址,即三级指针指向二级指针。

6、传递指针给函数:通过引用或地址传递参数,使传递的参数在调用函数中被改变。

7、从函数返回指针(地址)

返回静态局部变量地址:

由于函数中的局部变量存储在内存的栈区,当函数调用结束后,局部变量所占的内存地址便被释放了。

而static 变量的值存放在内存中的静态数据区,不会随着函数执行的结束而被清除,故能返回其地址。

声明:

int * getRandom()

二、函数指针

函数指针:指向函数的指针。

1、声明

int (*fun_ptr)(int,int); //声明一个指向同样参数、返回值的函数指针类型

2、定义

fun_ptr=fun;

3、调用:可直接用指针调用。

fun_ptr(a,b);

例:

typedef void(*FunType)(int);
//typedef关键字,定义一个名为FunType函数指针类型,而不是一个FunType变量。
//形式同 typedef int* PINT;
void myFun(int x);
void hisFun(int x);
void herFun(int x);
void callFun(FunType fp,int x);
int main()
{
    callFun(myFun,100);//传入函数指针常量,作为回调函数
    callFun(hisFun,200);
    callFun(herFun,300);

​	return 0;
}

void callFun(FunType fp,int x)
{
    fp(x);//通过fp的指针执行传递进来的函数,注意fp所指的函数有一个参数
}

void myFun(int x)
{
    printf("myFun: %d\n",x);
}
void hisFun(int x)
{
    printf("hisFun: %d\n",x);
}
void herFun(int x)
{
    printf("herFun: %d\n",x);
}

三、回调函数

1、回调函数就是一个通过函数指针调用的函数。

函数指针作为某个函数的参数:不同功能的函数有相同的形式,将需要调用的函数指针作为参数传递给一个函数,在函数内使用指针调用对应函数。

回调函数最大的意义在于解耦,降低代码之间的耦合度。

int Callback_1(int a)   ///< 回调函数1
{
    printf("Hello, this is Callback_1: a = %d ", a);
    return 0;
}
​
int Callback_2(int b)  ///< 回调函数2
{
    printf("Hello, this is Callback_2: b = %d ", b);
    return 0;
}
​
int Callback_3(int c)   ///< 回调函数3
{
    printf("Hello, this is Callback_3: c = %d ", c);
    return 0;
}
​
int Handle(int x, int (*Callback)(int)) ///< 注意这里用到的函数指针定义
{
    Callback(x);
}
​
int main()
{
    Handle(4, Callback_1);
    Handle(5, Callback_2);
    Handle(6, Callback_3);
    return 0;
}

可以看到,Handle()函数里面的参数是一个指针,在main()函数里调用Handle()函数的时候,给它传入了函数Callback_1()/Callback_2()/Callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。

2、回调函数实例(转载,以后可能需要)

一个GPRS模块联网的小项目,使用过的同学大概知道2G、4G、NB等模块要想实现无线联网功能都需要经历模块上电初始化、注册网络、查询网络信息质量、连接服务器等步骤,这里的的例子就是,利用一个状态机函数(根据不同状态依次调用不同实现方法的函数),通过回调函数的方式依次调用不同的函数,实现模块联网功能,如下:

/*********  工作状态处理  *********/
typedef struct
{
    uint8_t mStatus;
    uint8_t (* Funtion)(void); //函数指针的形式
} M26_WorkStatus_TypeDef;  //M26的工作状态集合调用函数

/**********************************************
** >M26工作状态集合函数
***********************************************/
M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
{    
    {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //模块关机
    {GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //模块开机
    {GPRS_NETWORK_Start,   M26_Work_Init  }, //管脚初始化
    {GPRS_NETWORK_CONF,  M26_NET_Config  }, /AT指令配置
    {GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //连接调度中心  
    {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //等待调度中心回复 
    {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //连接前置机
    {GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //等待前置机回复
    {GPRS_NETWORK_COMM,  M26_COMM   }, //正常工作    
    {GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //等待信号回复
    {GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //获取信号值
    {GPRS_NETWORK_RESTART,  M26_RESET   }, //模块重启
}
/**********************************************
** >M26模块工作状态机,依次调用里面的12个函数   
***********************************************/
uint8_t M26_WorkStatus_Call(uint8_t Start)
{
    uint8_t i = 0;
    for(i = 0; i < 12; i++)
    {
        if(Start == M26_WorkStatus_Tab[i].mStatus)
        {          
      return M26_WorkStatus_Tab[i].Funtion();
        }
    }
    return 0;
}

所以,如果有人想做个NB模块联网项目,可以copy上面的框架,只需要修改回调函数内部的具体实现,或者增加、减少回调函数,就可以很简洁快速的实现模块联网。

参考链接:C语言回调函数详解(全网最全)-优快云博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值