回调函数的作用

对指针的应用是C语言编程的精髓所在,而回调函数就是C语言里面对函数指针的高级应用。简而言之,回调函数是一个通过函数指针调用的函数。如果你把函数指针(函数的入口地址)传递给另一个函数,当这个函数指针被用来调用它所指向的函数时,我们就说这个函数是回调函数。

为什么要使用回调函数呢?我们先看一个小例子:

 1         Node * Search_List (Node * node, const int value)
 2         {
 3                 while (node != NULL)
 4                 {
 5                         if (node -> value == value)
 6                         {
 7                                 break;
 8                         }
 9                         node = node -> next;
10                 }
11                 return node;
12         }

这个函数用于在一个单向链表中查找一个指定的值,返回保存这个值的节点。它的参数是指向这个链表第一个节点的指针以及要查找的值。这个函数看上去很简单,但是我们考虑一个问题:它只能适用于值为整数的链表,如果查找一个字符串链表,我们不得不再写一个函数,其实大部分代码和现在这个函数相同,只是第二个参数的类型和比较的方法不同。

其实我们更希望令查找函数与类型无关,这样它就能用于查找存放任何类型值的链表了,因此必须改变比较的方式,而借助回调函数就可以达到这个目的。我们编写一个函数(回调函数),用于比较两个同类型的值,然后把一个指向这个函数的指针作为参数传递给查找函数,查找函数调用这个比较函数来执行比较,采用这个方法,任何类型的值得都可以进行比较。

我们还必须给查找函数传递一个指向待比较的值的指针而不是值本身,也就是一个void *类型的形参,这个指针会传递给回调函数,进行最终的比较。这样的修改可以让我们传递指向任何类型的指针到查找函数,从而完成对任何类型的比较,这就是指针的好处,我们无法将字符串、数组或者结构体作为参数传递给函数,但是指向它们的指针却可以。

现在,我们的查找函数就可以这样实现:

 1         NODE *Search_List(NODE *node, int (*compare)(void const *, void const *) ,  2         void const *desired_value);
 3         {
 4                 while (node != NULL)
 5                 {
 6                         if (compare((node->value_address), desired_value) == 0)
 7                         {
 8                                 break;
 9                         }
10                         node = node->next;
11                 }
12                 return node;
13         }

可以看到,用户将一个函数指针传递给查找函数,后者将回调这个函数。

注意这里我们的链表节点是这样定义的:

1 typedef struct list
2         {
3                 void *value_address;
4                 struct list *next;
5         }NODE;

这样定义可以让NODE *类型的指针指向存储任何类型数据的链表节点。而value_address就是指向具体数据的指针,我们把它定义为void *,表示一个指向未知类型的指针,这样链表就可以存储任何类型的数据了,而我们传递给查找函数Search_List的第一个参数就可以统一表示为:NODE *,否则,还是要分别写查找函数以适应存储不同数据类型的链表。

现在,查找函数与类型无关,因为它不进行实际的比较,因此,我们必须编写针对不同类型的比较函数,这是很容易实现的,因为调用者知道链表中所包含的值的类型,如果创建几个分别包含不同类型值的链表,为每种类型编写一个比较函数就允许单个查找函数作用于所有类型的链表。

下面是一个比较函数,用于在一个整型链表中查找:

注意强制类型转换,比较函数的参数必须被声明为void *以匹配查找函数的原型,然后强制转换为(int *)类型用于比较整型。

 1         int int_compare(void const *a, void const *b)
 2         {
 3                 if (*(int *)a == *(int *)b)
 4                 {
 5                         return 0;
 6                 }
 7                 else
 8                 {
 9                         return -1;
10                 }
11         }

这个函数可以这样被使用:

desired_node = Search_List(root, int_compare, &desired_int_value);

如果你希望在一个字符串链表中进行查找,下面的代码就可以完成任务:

desired_node = Search_List(root, strcmp, “abcdefg”);

正好库函数strcmp所执行的比较和我们需要的一样,不过gcc会发出警告信息:因为strcmp的参数被声明为const char *而不是void const *。

上面的例子展示了回调函数的基本原理和用法,回调函数的应用是非常广泛的。通常,当我们想通过一个统一接口实现不同内容的时候,用回调函数来实现就非常合适。任何时候,如果你所编写的函数必须能够在不同的时刻执行不同的类型的工作或者执行只能由函数调用者定义的工作,你都可以用回调函数来实现。许多窗口系统就是使用回调函数连接多个动作,如拖拽鼠标和点击按钮来指定调用用户程序中的某个特定函数。

时间: 2024-07-30 15:02:20

回调函数的作用的相关文章

js中的回调函数的理解和使用方法

一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为函数实际上是一种对象,它可以存储在变量中,通过参数传递给另一个函数,在函数内部创建,从函数中返回结果值",因为函数是内置对象,我们可以将它作为参数传递给另一个函数,到函数中执行,甚至执行后将它返回,它一直被"专业的程序员"看作是一种难懂的技术. 回调函数的英文解释为: A callback is a functi

Java(Android)回调函数详解

一.前言 本周有位入行开发不久的朋友问我回调究竟是个什么概念,在网上看了很多的回调函数解释,但是越看越乱.虽然回调函数这个梗已经不新鲜了,这里还是用书面的形式记录下. 如果有了解的,就无需再看. 二.概念 概念上,这里引用百度百科的解释,如下: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条

回调函数(真好理解)

回调函数 在看LWIP时,见到用回调函数,再看某老外公司OPC源代码时,见到用回调函数.看我国内某些代码(我公司软件等)时没用到.于是,我对回调函数产生了很大的好奇.以前,我写VC程序时用到过回调函数,但是没有用C语言来使用.最近,看到国外大量的经典代码中广泛使用了回调函数(LWIP.某两个公司的OPC程序等),都是C语言来实现的,而不是VC windows程序中别人实现自己使用的那种. 为了弄明白这种函数的奥妙,首先提出三个问题: 1.        回调函数是什么东西? 2.        

深入浅出剖析C语言函数指针与回调函数(一)【转】

本文转载自:http://blog.csdn.net/morixinguan/article/details/65494239 关于静态库和动态库的使用和制作方法. http://blog.csdn.NET/morixinguan/article/details/52451612 今天我们要搞明白的一个概念叫回调函数. 什么是回调函数? 百度的权威解释如下: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说

函数指针,回调函数

函数指针的定义:返回值类型 ( * 指针变量名) (形参列表); 1:"返回值类型"说明函数的返回类型,"(指针变量名 )"中的括号不能省,括号改变了运算符的优先级.若省略整体则成为一个函数说明,说明了一个返回的数据类型是指针的函数,后面的"形参列表"表示指针变量指向的函数所带的参数列表. int func(int x); /* 声明一个函数 */ int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func

回调函数 与函数指针

函数指针的定义:返回值类型 ( * 指针变量名) (形参列表); 1:"返回值类型"说明函数的返回类型,"(指针变量名 )"中的括号不能省,括号改变了运算符的优先级.若省略整体则成为一个函数说明,说明了一个返回的数据类型是指针的函数,后面的"形参列表"表示指针变量指向的函数所带的参数列表. int func(int x); /* 声明一个函数 */ int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func

委托&指针函数&回调函数

委托 委托是一种数据类型,像类一样(可以声明委托类型变量)方法参数可以是int string 类类型. //1 //委托小结 //1 定义一个委托需要delegate关键字 //public delegate void WriteTimeToAny(); //2 委托用来存储的方法要与定义的委托类型相一致 //3 委托是一个数据类型,用时需要传递一个变量,可以使用关键字new也可以不使用 //使用委托的意义 //主要是注入代码,写入一个委托类型方法方便以后使用时可以用实现相应的功能 //2 //

js中回调函数的三种写法

回调函数的三种写法: 1.通过指针来调用 2.通过匿名函数来调用 3.定义与执行同时进行 // 通过指针来调用 function math(num1,num2,callback){ return callback(num1 , num2); } function aa(num1,num2){ return num1 + num2; } function bb(num1,num2){ return num1 - num2; } console.log( math(2,1,aa) ); // 3 c

回调函数2

上面一篇介绍了一下对回调函数的基本理解和一个简单的比较抽象的例子,那么下面通过一个比较实际的例子来看看对回调函数的运用 比如现在我们要写一个测试类方法运行时间的程序,按照一般的程序思维,我们会写出下面的代码 public   class  TestTime { /** * 一个用来被测试的方法,进行了一个比较耗时的循环 */ public   static   void  testMethod(){ for ( int  i= 0 ; i< 100000000 ; i++){ } } /** *