原文出处:https://segmentfault.com/a/1190000008293902?utm_source=tag-newest

前言:

  如不懂函数指针,请先查阅关于函数指针内容的资料(https://www.cnblogs.com/waphoo-blogs/p/10980281.html),有助于你更好理解下文内容

什么是回调函数

我们先来看看百度百科是如何定义回调函数的:

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

这段话比较长,也比较绕口。下面我通过一幅图来说明什么是回调:

假设我们要使用一个排序函数来对数组进行排序,那么在主程序(Main program)中,我们先通过库,选择一个库排序函数(Library function)。但排序算法有很多,有冒泡排序,选择排序,快速排序,归并排序。同时,我们也可能需要对特殊的对象进行排序,比如特定的结构体等。库函数会根据我们的需要选择一种排序算法,然后调用实现该算法的函数来完成排序工作。这个被调用的排序函数就是回调函数(Callback function)。

结合这幅图和上面对回调函数的解释,我们可以发现,要实现回调函数,最关键的一点就是要将函数的指针传递给一个函数(上图中是库函数),然后这个函数就可以通过这个指针来调用回调函数了。注意,回调函数并不是C语言特有的,几乎任何语言都有回调函数。在C语言中,我们通过使用函数指针来实现回调函数。那函数指针是什么?不着急,下面我们就先来看看什么是函数指针。

回调函数

现在我们回到正题,来看看回调函数到底是怎样实现的。下面是一个四则运算的简单回调函数例子:

#include <stdio.h>
#include <stdlib.h> /****************************************
* 函数指针结构体
***************************************/
typedef struct _OP {
float (*p_add)(float, float);
float (*p_sub)(float, float);
float (*p_mul)(float, float);
float (*p_div)(float, float);
} OP; /****************************************
* 加减乘除函数
***************************************/
float ADD(float a, float b)
{
return a + b;
} float SUB(float a, float b)
{
return a - b;
} float MUL(float a, float b)
{
return a * b;
} float DIV(float a, float b)
{
return a / b;
} /****************************************
* 初始化函数指针
***************************************/
void init_op(OP *op)
{
op->p_add = ADD;
op->p_sub = SUB;
op->p_mul = &MUL;
op->p_div = &DIV;
} /****************************************
* 库函数
***************************************/
float add_sub_mul_div(float a, float b, float (*op_func)(float, float))
{
return (*op_func)(a, b);
} int main(int argc, char *argv[])
{
OP *op = (OP *)malloc(sizeof(OP));
init_op(op); /* 直接使用函数指针调用函数 */
printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n", (op->p_add)(1.3, 2.2), (*op->p_sub)(1.3, 2.2),
(op->p_mul)(1.3, 2.2), (*op->p_div)(1.3, 2.2)); /* 调用回调函数 */
printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n",
add_sub_mul_div(1.3, 2.2, ADD),
add_sub_mul_div(1.3, 2.2, SUB),
add_sub_mul_div(1.3, 2.2, MUL),
add_sub_mul_div(1.3, 2.2, DIV)); return ;
}
这个例子有点长,我一步步地来讲解如何使用回调函数。 第一步
要完成加减乘除,我们需要定义四个函数分别实现加减乘除的运算功能,这几个函数就是: /****************************************
* 加减乘除函数
***************************************/
float ADD(float a, float b)
{
return a + b;
} float SUB(float a, float b)
{
return a - b;
} float MUL(float a, float b)
{
return a * b;
} float DIV(float a, float b)
{
return a / b;
}

第二步

我们需要定义四个函数指针分别指向这四个函数:

/****************************************
* 函数指针结构体
***************************************/
typedef struct _OP {
float (*p_add)(float, float);
float (*p_sub)(float, float);
float (*p_mul)(float, float);
float (*p_div)(float, float);
} OP; /****************************************
* 初始化函数指针
***************************************/
void init_op(OP *op)
{
op->p_add = ADD;
op->p_sub = SUB;
op->p_mul = &MUL;
op->p_div = &DIV;
}

第三步

我们需要创建一个“库函数”,这个函数以函数指针为参数,通过它来调用不同的函数:

/****************************************
* 库函数
***************************************/
float add_sub_mul_div(float a, float b, float (*op_func)(float, float))
{
return (*op_func)(a, b);
}

第四步

当这几部都完成后,我们就可以开始调用回调函数了:

/* 调用回调函数 */
printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n",
add_sub_mul_div(1.3, 2.2, op->p_add),
add_sub_mul_div(1.3, 2.2, op->p_sub),
add_sub_mul_div(1.3, 2.2, MUL),
add_sub_mul_div(1.3, 2.2, DIV));

简单的四部便可以实现回调函数。在这四步中,我们甚至可以省略第二步,直接将函数名传入“库函数”,比如上面的乘法和除法运算。回调函数的核心就是函数指针,只要搞懂了函数指针再学回调函数,那真是手到擒来了。

如有侵权,望告知删帖。

转·带你用实例理解C语言回调函数的更多相关文章

  1. 对c语言回调函数的理解

    对于回调函数,可以简单的理解为一种特别的函数调用方法,我们可以对比一下回调函数与普通函数在调用方法上的区别. 1. 普通函数调用 一般为实现方在其函数体执行过程中直接调用. 代码示例: #includ ...

  2. C语言回调函数详解

    1. 什么是回调函数? 回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义.我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类 ...

  3. 【转】一文搞懂C语言回调函数

    转:https://segmentfault.com/a/1190000008293902?utm_source=tag-newest 什么是回调函数 我们先来看看百度百科是如何定义回调函数的: 回调 ...

  4. 透过一个实例理解C++语言的explicit关键字

    我们先看一段代码:    建立people.cpp 文件,然后输入下列内容:class People{    public:      int age;     explicit People (in ...

  5. C语言回调函数

    Callbacks have a wide variety of uses. For example, imagine a function that reads a configuration fi ...

  6. C语言回调函数总结

    /* Main program ---calls--> Library function ---calls--> Callback funtion */ #include <stdi ...

  7. javascript 理解和使用回调函数

    在javascript中,function是内置的类对象,也就是说它是一种类型的对象,可以和其他String.Array.Number.Objec类的对象一样用于内置对象的管理.因为function实 ...

  8. JS中的回调函数实例浅析

    本文实例讲述了JS中的回调函数.分享给大家供大家参考,具体如下: 在说回调函数之前,不妨先看一段代码,相信有点js基础的同学都能明白他的含义: ? 1 2 3 document.getElementB ...

  9. Python回调函数用法实例详解

    本文实例讲述了Python回调函数用法.分享给大家供大家参考.具体分析如下: 一.百度百科上对回调函数的解释: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函 ...

随机推荐

  1. 【每日一包0001】is-sorted

    github地址:https://github.com/ABCDdouyae... is-sorted 用于判断数组是否被排序了 文档地址:https://www.npmjs.com/package/ ...

  2. MyEclipse使用教程:导航代码(一)

    [MyEclipse CI 2019.4.0安装包下载] 无论是在文件之间导航还是在文件中导航,都可以使用大量导航工具来加快工作流程.目前这些导航工具可在MyEclipse,CodeMix中使用. 快 ...

  3. oracle 数据库安装及jdbc的连接

    今天,我在oracle的官网下载了数据库并进行安装,其中遇到一些问题,在此进行记录. 1.下载,之后,按照网上的教程进行安装,开始遇到 下载之后出现11g 出现ins13001环境不满足最低要求 这个 ...

  4. Acwing-282-石子合并(区间DP)

    链接: https://www.acwing.com/problem/content/284/ 题意: 设有N堆石子排成一排,其编号为1,2,3,-,N. 每堆石子有一定的质量,可以用一个整数来描述, ...

  5. c#图像处理的简单算法

    原文链接:https://blog.csdn.net/wchstrife/article/details/78984735 使用C#进行图像处理前言之前一直认为图像处理是一件很高大上的事情,在一门选修 ...

  6. qt5-自定义类

    创建一个自定义按钮类: 右击工程目录--->--->--->---> ---> --->

  7. es6的Map结构

    es6的Map结构主要解决Object的键名只能是单一属性的问题.它可以是字符串,对象,数组,等等 其中有个问题要注意一下,就是 var map = new Map(); map.set(['a'], ...

  8. 2017noip总结

    day0 酒店位置很好,旁边就是玉树公园,3公里处还有万达广场: 晚上去万达吃喝玩乐, 不过,打车等了好久,手机还没电了. 同时水杯还在广州扎根了...(暗示后文悲惨结局) day1 8:30 监考老 ...

  9. C# MVC的默认页

    MVC的默认页,其实是默认路由设置启动哪一个Controller的哪一个Action,在根目录的Global.asax.cs里面设置.是MVC项目里面的路由.將下面的controller和action ...

  10. websocket协议解决消息发送问题 Could not decode a text frame as UTF-8.

    在使用websocket 时出现了Could not decode a text frame as UTF-8 首次连接成功当发送消息时,出现了编码作错误 第一请求页面时,连接成功 当发送消息时,不加 ...