[置顶] 成为C++高手之回调函数

上一节的排序函数只能正向排序,那我们需要反向排序怎么办?可以增加一个参数嘛,传入TRUE,就表示要正向排,传入FALSE,就表示要反向排。要改变排序方向,只需改变两项比较时是用大于号还是小于号即可。但是这里有更高级的玩法,即传入的参数不是一个BOOL型值,而是一个函数指针。

函数名本身就是一个指针,调试时看函数名,其值就是一个地址。但在逻辑上不能把函数名叫函数指针,必须另创建一个指针指向这个函数,通过这个指针调用函数才叫回调。

函数指指与变量指针没实质区别,都是保存一个表示内存位置的整数,但编译器必须能区分指针的类型才行。所以函数指针在定义时必须指定其类型。所以要为函数定义类型。函数类型是由函数返回值类型、参数数量、参数类型决定,与函数的实现无关。就是长一个样的函数都是同一类型。

我们这里增加一个参数,传入的函数指针指向一个比较函数,仅代替“arr[j]>arr[j+1]”部分。比较函数必须有两个参数指向要比较的元素的序号,返回必须是BOOL型数据,表示比较结果。if语句跟据比较函数返回值决定是否交换位置。

#include <stdio.h>
//定义比较函数类型
typedef int (*CompareFunc)(int *,int ,int );
//前置声明排序函数,第三个参数是比较函数类型
void sort(int * ,int ,CompareFunc);

//返回非0数表示比较成功,返回0表示失败
int compare1(int *arr,int a,int b){
    return arr[a]>arr[b];
}
int compare2(int *arr,int a,int b){
    return arr[a]<arr[b];
}

int main(int argc, const char * argv[]) {

    int arr[]={22,33,45,1,2,7,66,554,23424234,22};

    //排序,第三个参数可以传入两个比较函数之一
    sort(arr,sizeof(arr)/sizeof(int),compare1);

    //打印排序后的数组
    for(int i=0;i<sizeof(arr)/sizeof(int);i++){
        printf("%d ",arr[i]);
    }

    return 0;
}

//第一个参数是要排序的数组,第二个是数组两元素的数量
void sort(int *arr ,int count,CompareFunc compare_func){
    int i;
    //外层循环是倒着来的
    for(i=count-1;i>0;i--){
        int j;
        for(j=0;j<i;j++){
            //调用比较函数进行比较
            if(compare_func(arr,j,i)){
                int tmp = arr[j];
                arr[j]=arr[i];
                arr[i]=tmp;
            }
        }
    }
}

改用回调函数有什么好处呢?此处并不明显,甚至更麻烦。但试想这种情况:如果我们数组中不是简单数值,而是一个结构。比如扑克牌,一张牌至少有两个属性:花色和点数,对应到结构中就是两个成员变量。当牌发到玩家手中后,是乱序的,玩家需要整理好其顺序。不同的游戏有不同的排序规则,那我们可以为每种游戏规则都写一个不同的排序函数,或者这样做:排序函数固定,只为每种不同的游戏写不同的比较函数。这增强了排序代码的重用性。
上一篇:成为C++高手之for循环

你可能感兴趣的:(C语言)