通过冒泡排序(C语言实现)学习回调函数设计原理

来源:互联网 发布:紫峰抢单软件好用吗 编辑:程序博客网 时间:2024/05/23 19:01

转载请注明出处:http://blog.csdn.net/ecorefeng

作者:朱克锋

 

对于回调函数的概念有很多种,下面我列举一些常见的看法:
a:回调函数是一个很有用,也很重要的概念。当发生某种事件时,系统或其他函数将会自动调用你定义的一段函数。
b:回调函数就相当于一个中断处理函数,由系统在符合你设定的条件时自动调用。为此,你需要做三件事:1,声明;2,定义;3,设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。
c:所谓回调函数就是按照一定的形式由你定义并编写实现内容,当发生某种事件时,而由系统或其它函数来调用的函数。使用回调函数实际上就是在调用某个函数时,将自己编写的一个函数的地址作为参数传递给那个函数。而那个函数在需要的时候,也就是某种事情发生的时候,利用传递的函数地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。回调函数只能是全局函数,或者是静态函数,因为这个函数只是在这个类中使用,所以为了维护类的完整性,我们用类的静态成员函数来做回调函数。

对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。下面解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题(在开始之前,假设你已经熟知了函数指针)。
(1)什么是回调函数?为什么要使用回调函数?  
简而言之,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。  
因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。  
如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、 shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、float、 string),此时,该怎么办呢?可以使用函数指针,并进行回调。
接下来我将通过一个冒泡排序的例子来说明,给读者一个直观的感受
代码实现如下:

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <malloc.h>
/*
* File:   darray.c:回调函数冒泡排序函数实现
* Author: ecorefeng
* Created on 2010年8月
*/
/*
*定义一个用于自动测试的宏(关于自动测试请阅读我的博客文章《自动测试的优劣》)
*/
#define  return_val_if_fail(p, val)/
    if(!(p)){printf("%s:%d"#p" failed", __func__, __LINE__); return val; }
*/
/*
*定义一个回调函数原型,用于回调
*/
typedef int (*CompFunc)(void *ctx, void *data);
/*
*功能:实现冒泡排序
*参数:array:要排序的数组 compfunc:回调的用于比较的函数  array_len:数组长度
*返回:
*/
int  darray_b_sort(void **array,CompFunc compfunc, int array_len)
{
    return_val_if_fail(array !=NULL&&compfunc !=NULL, 1);

    int len = 0;
    int max = 0;
    int index = 0;

    for(len = array_len - 1; len > 0; len--)
    {
        for(index = 1, max = 0; index < len; index++)
        {
            if(compfunc(array[index], array[max]) > 0)
            {
                max = index;
            }
   
        }
        if(compfunc(array[max], array[len]) > 0)
        {
            void *data = array[max];
            array[max] = array[len];
            array[len] = data;
        }

        //int i = 0;
        //for(i = 0; i < 6; i++)
        //{
            //printf("%d/n",array[i]);
        //    assert(array[i] >= array[i-1]);
        //}
        //printf("......................./n");

    }

    return 0;
}
/*
*功能:随机生成一个数组
*参数:num:数组长度
*返回:数组指针
*/

static void **int_array_create(int num)
{
    int i = 0;
    int *array = (int *)malloc(sizeof(int) * num);
   
    for(i = 0; i < num; i++)
    {
        array[i] = rand();
        //printf("%d/n",array[i]);

    }
    //printf("......................./n");
    return(void **)array;

}
/*
*功能:实现比较
*参数:compfunc:回调的用于比较的函数 num:数组长度
*返回:数组指针
*/
static void sort_test_asc_or_desc(CompFunc compfunc, int num)
{
    void **array = int_array_create(num);
    darray_b_sort(array, compfunc, num);

    int i = 0;
    for(i = 0; i < num; i++)
    {
        printf("%d/n",array[i]);
    //    assert(array[i] >= array[i-1]);
    }
   
    free(array);
}
/*
*功能:实现比较函数(升序)
*参数:指针
*返回:比较结果:大于0、小于0;
*/
int int_sort_compfunc_asc(void *num1,  void *num2)
{
    return (int)num1 - (int)num2;
}
/*
*功能:实现比较函数(降序)
*参数:指针
*返回:比较结果:大于0、小于0;
*/
int int_sort_compfunc_desc(void *num1,  void *num2)
{
    return (int)num2 - (int)num1;
}

int main(int argc, char *argv[])
{
    sort_test_asc_or_desc(int_sort_compfunc_asc, 6);
    printf("................/n");
    sort_test_asc_or_desc(int_sort_compfunc_desc, 10);

    return 0;
}

代码注释已经对代码作了详细的说明,对于代码的解释我就不再多说了,请读者仔细体会回调函数的用法。

附注: 
回调可用于通知机制,例如,有时要在程序中设置一个计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调,来通知我们的程序事件已经发生。实际上,SetTimer()API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。
  
另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

原创粉丝点击