C&C++知识难点
C&C++学习难点
前言
回调函数是什么?为什么要有回调函数?有什么用?主要用在哪里?
一、函数指针
1.函数指针定义
函数指针和其他指针一样,间接访问函数,在对函数指针执行间接问之前必须把它初始化为指向某个函数。
int func(int );
int (*p_func)(int)=&func;
初始化表达式中的&操作符是可选的,因为函数名被使用时总是由编译器把它转换为函数指针。
&操作符只是显式地说明了编译器将隐式执行的任务。
在函数指针被声明并且初始化之后,我们就可以使用三种方式调用函数
int ans;
ans=func(3);
ans=(*p_func)(25);
ans=p_func(25);
第1条语句简单地使用名字调用函数func,它的执行过程是,函数名func首先被转换为一个函数指针,该指针指定函数在内存中的位置。然后,函数调用操作符调用该函数,执行开始于这个地址的代码。(函数名称类似数组名称,字符数组名称,都是地址)
第2条语句对p_func执行间接访问操作,它把函数指针转换为一个函数名。这个转换并不是真正需要的,因为编译器在执行函数调用操作符之前又会把它转换回去。不过,这条语句的效果和第1条语句是完全一样的。
第3条语句和前两条语句的效果是一样的。间接访问操作并非必需,因为编译器需要的是一个函数指针。这个例子显示了函数指针通常是如何使用的。
什么时候我们应该使用函数指针呢?最常见的用途是把函数指针作为参数传递给函数。而回调函数会用到。
二、回调函数
1.简单例子
这里有一个简单的函数,它用于在一个单链表中查找一个值。它的参数是一个指向链表第1个节点的指针以及那个需要查找的值
Node search_list( Node *node, int const value)
{while( node !=NULL )
{ if(node->value == value)
break;
node =node->link ;
}
return node;
}
这个函数看上去相当简单,但它只适用于值为整数的链表。如果你需要在一个字符串链表中查找,你不得不另外编写一个函数。这个函数和上面那个函数的绝大部分代码相同,只是第2个参数的类型以及节点值的比较方法不同。
为了比较任何类型的值,我们想出一种方法,使用函数指针。调用者编函数用于比较两个值,然后把一个指向这个函数的指针作为参数传递给查找函数。然后查找函数调用这个函数来执行值的比较。使用这种方法,任何类型的值都可以进行比较。(通过指针的方式传递一个比较函数)
2.改进后例子
代码如下(示例):
#include <stdio.h>
#include "node.h"
Node * search_list(Node*node,void const *value,
int (*compare)(void const*,void const*))
{
while(node!=NULL)
{
if(compare(&node->value,value)==0)
break;
node=node->link;
}
return node;
}
// comapare函数
int compare(void const*a,void const *b)
{
if( *(int*)a==*(int*)b)
return 0;
else
return 1;
}
注意强制类型转换:比较函数的参数必须声明为void*
以匹配查找函数的原型,然后它们再强制转换为int*
类型,用于比较整型值。
调用方式
Node* desired_node=serach_list(root,&desired_value,compare);
如果想要在字符串链表中进行查我,下面的代码可以完成这项务
desire_node=search_list(root,"desire_value",strcmp)
巧妙的是,库函数 strcmp所执行的比较和我们需要的完全一样,不过有些编译器会发出警告信息,因为它的参数被声明为char*
而不是void*
。
总结
回调函数( callback function)定义:用数指针作为参数传递给其他函数,后者将“回调”用户的函数。任何时候,如果你所编写的函数必须能够在不同的时刻执行不同类型的工作或者执行只能由函数调用者定义的工作,你都可以使用回调函数。经常使用在排序等函数中用来比较两个自定义元素比如,C++中的结构体,java中自定义的类。