Chinaunix首页 | 论坛 | 博客
  • 博客访问: 732369
  • 博文数量: 134
  • 博客积分: 3207
  • 博客等级: 中校
  • 技术积分: 1995
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-01 20:47
文章分类

全部博文(134)

文章存档

2022年(1)

2020年(7)

2018年(2)

2016年(5)

2015年(14)

2014年(21)

2013年(3)

2012年(1)

2011年(15)

2010年(30)

2009年(35)

分类: LINUX

2010-07-19 14:31:23

回调函数是一个通过函数指针调用的函数。如果你把函数指针(函数的入口地址)传递给另一个函数,当这个函数指针被用来调用它所指向的函数时,我们就说这个函数是回调函数。
回调函数实例应用:
1、问题描述。
先看一个小例子:
Link Search_List (Link L, int value) 
        Link r;
r = L->next;
        while (r!= NULL) 
        { 
         if (r->value == value) 
                { 
                        break; 
                } 
                r = r->next; 
        } 
                return r; 
}
这个函数用于在一个单向链表中查找一个指定的值,返回保存这个值的节点。这个函数看上去很简单,但是我们考虑一个问题:它只能适用于值为整数的链表,如果查找一个字符串链表,我们不得不再写一个函数,其实大部分代码和现在这个函数相同,只是第二个参数的类型和比较的方法不同。

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

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

现在,我们的查找函数就可以这样实现: 
typedef int (*Compare)(void * ,void *);
Compare com;
Link Seach_List(Link L, Compare c, void *value)
{
Link r;
r = L->next;
com = c;
while(r != NULL){
if((com(r->data, value)) == 0)
break;
r = r->next;
}
return r;
}
可以看到,用户将一个函数指针传递给查找函数,后者将回调这个函数。
注意这里我们的链表节点是这样定义的: 
typedef struct node{
    void *data;
    struct node *next;
}Nnode,*Link;
这样定义可以让 Link类型的指针指向存储任何类型数据的链表节点。
现在,查找函数与类型无关,因为它不进行实际的比较,因此,我们必须编写针对不同类型的比较函数,这是很容易实现的,因为调用者知道链表中所包含的值的类型,如果创建几个分别包含不同类型值的链表,为每种类型编写一个比较函数就允许单个查找函数作用于所有类型的链表。 

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

注意强制类型转换,比较函数的参数必须被声明为void *以匹配查找函数的原型,然后强制转换为链表中具体的数据类型用于比较。 
int compare(void *a, void *b)
{
if(*((TYPE *)a) == *((TYPE *)b))
return 0;
else 
return -1;
}

具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

typedef long TYPE;

typedef int (*Compare)(void * ,void *);

typedef struct node{
    void *data;
    struct node *next;
}Nnode,*Link;

Compare com ;

/*
 *Fun Name: InitLink
 *Fun Could: Create a Link
 *Input Num: none
 *Output Num: L
 */

Link InitLink()
{
    Link L;
    L = (Link)malloc(sizeof(Nnode));
    L->next = NULL;
    return L;
}

/*
 *Fun Name: InsertL
 *Fun Could: Insert a Link
 *Input Num: L,e
 *Output Num: L
 */

Link InsertL(Link L, void *e)
{
    Link s,r;
    r = L;
    while(r->next != NULL)
        r = r->next;
    s = (Link)malloc(sizeof(Nnode));
    s->data = e;
    r->next = s;
    s->next = NULL;
    return L;
}

int compare(void *a, void *b)
{
    if(*((TYPE *)a) == *((TYPE *)b))
        return 0;
    else
        return -1;
}

/*
 *
 *
 */

Link Seach_List(Link L, Compare c, void *value)
{
    Link r;
    r = L->next;
    com = c;
    while(r != NULL){
        if((com(r->data, value)) == 0)
            break;
        r = r->next;
    }
    return r;
}

/*
 *Fun Name: DeleteL
 *Fun Could: Delete a jiedian
 *Input Num: L,i
 *Output Num: L
 */

Link DeleteL(Link L, int i)
{
    Link r,p;
    int i1,i2;
    r = p = L;
    i1 = i2 = i;
    while(i1 != 1){
        p = p->next;
        i1--;
    }
    while(i2 != 0){
        r = r->next;
        i2--;
    }
    p->next = r->next;
    free(r);
    return L;
}

/*
 *Test
 */

void test_one()
{
    Link L,r;
    int i;
    TYPE value = 54;
    TYPE temp[15];
    memset(temp, 0, 15);
    for (i = 0; i < 10; i++)
        temp[i] = (i+48);
    L = InitLink();
    for(i = 0;i < 10; i++){
        L = InsertL(L, (temp+i));
    }
    r = L->next;
    while(r != NULL){
        printf("%ld\n", *((TYPE *)r->data));
        r = r->next;
    }
    r = Seach_List(L, compare, &value);
    printf("seach :%ld\n", *(TYPE *)r->data);
}

void test_str()
{
    Link L, r;
    int i;
    char *str = "peng";
    char *a[5]={
    "lan",
    "peng",
    "shell",
    "linux",
    "bash"
    };
    L = InitLink();
    for(i = 0; i < 5; i++)
        L = InsertL(L, a[i]);
    r = L->next;
    while(r != NULL){
        printf("%s\n", (char *)r->data);
        r = r->next;
    }
    r = Seach_List(L, strcmp, str);
    printf("seach :%s\n", (char *)r->data);
}

int main()
{
    test_one();
    test_str();
    return 0;
}


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