动态排序实例(函数回调)

需求分析

1.定义一个Teacher结构体包括:姓名,性别,年龄,员工编号,评分
2.定义一个对结构体数组排序的函数,包括一个返回值为BOOl类型的回调函数,实现按照不同的条件对结构体成员排序
3.定义一个打印所有老师信息的函数
4.实现多个返回值为BOOL类型的函数,用来判断排序中的if交换变量条件
5.定义一个判断并打印所有男老师和女老师的函数
6.定义一个枚举类型,和控制台输入功能的数字相对应
7.使用while循环实现重新输入功能,若输入功能以外的数字,则提示重新输入界面截图


函数声明

Teacher.h

//定义一个Teacher结构体
typedef struct teacher {
    char name[20];
    char gender;
    int age;
    int number;
    float score;
}Teacher;
//声明一个枚举和用户从控制台输入的功能数字对应
enum FunctionName {
    CompareNameByAscending = 1,
    CompareNameByDescending,
    CompareNumberByAscending,
    CompareNumberByDescending,
    CompareScoreByAscending,
    CompareScoreByDescending,
    PrintMaleTeacher,
    PrintFemaleTeacher
};
//打印一个Teacher的函数
void printTeacher(Teacher *teacher);
//声明一个函数指针类型,判断条件真假
typedef BOOL(*CompareFunctionPointer)(Teacher teacher1, Teacher teacher2);
//Teacher结构体数组排序函数
void sortTeachers(Teacher teacher[], int count, CompareFunctionPointer cfp);
//打印Teach结构体数组中所有老师信息
void printTeachers(Teacher *teachers, int count);
//按照名字升序排序
BOOL compareNameByAscending(Teacher teacher1, Teacher teacher2);
//按照名字降序排序
BOOL compareNameByDescending(Teacher teacher1, Teacher teacher2);
//按编号升序排序
BOOL compareNumberByAscending(Teacher teacher1, Teacher teacher2);
//按编号降序排序
BOOL compareNumberByDescending(Teacher teacher1, Teacher teacher2);
//按评分升序排序
BOOL compareScoreByAscending(Teacher teacher1, Teacher teacher2);
//按评分降序排序
BOOL compareScoreByDescending(Teacher teacher1, Teacher teacher2);
//输出全部男老师
void printMaleTeacher(Teacher *teachers, int count);
//输出全部女老师
void printFemaleTeacher(Teacher *teachers, int count);
//打印操作说明
void printInstructions();
//重命名输出男女老师函数指针
typedef void (*PrintByGender)(Teacher *teachers, int count);

函数实现


Teacher.m

//打印Teacher的函数
void printTeacher(Teacher *teacher) {
    printf("Name:%-20sGender:%-20cAge:%-20dNumber:%-20dScore:%-20f\n", teacher->name, teacher->gender, teacher->age, teacher->number, teacher->score);
}
//Teacher结构体数组排序函数
void sortTeachers(Teacher teacher[], int count, CompareFunctionPointer cfp) {
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if (cfp(teacher[j], teacher[j + 1])) {
                Teacher temp = teacher[j];
                teacher[j] = teacher[j + 1];
                teacher[j + 1] = temp;
            }
        }
    }
}
//打印Teach结构体数组中所有老师信息
void printTeachers(Teacher *teachers, int count) {
    for (int i = 0; i < count; i++) {
        printf("Name:%-20sGender:%-20cAge:%-20dNumber:%-20dScore:%-20f\n", teachers[i].name, teachers[i].gender, teachers[i].age, teachers[i].number, teachers[i].score);
    }
}
//按照名字升序排序
BOOL compareNameByAscending(Teacher teacher1, Teacher teacher2) {
    if (strcmp(teacher1.name, teacher2.name) > 0) {
        return YES;
    }
    return NO;
}
//按照名字降序排序
BOOL compareNameByDescending(Teacher teacher1, Teacher teacher2) {
    if (strcmp(teacher1.name, teacher2.name) < 0) {
        return YES;
    }
    return NO;
}
//按编号升序排序
BOOL compareNumberByAscending(Teacher teacher1, Teacher teacher2) {
    if (teacher1.number > teacher2.number) {
        return YES;
    }
    return NO;
}
//按编号降序排序
BOOL compareNumberByDescending(Teacher teacher1, Teacher teacher2) {
    if (teacher1.number < teacher2.number) {
        return YES;
    }
    return NO;
}
//按评分升序排序
BOOL compareScoreByAscending(Teacher teacher1, Teacher teacher2) {
    if (teacher1.score > teacher2.score) {
        return YES;
    }
    return NO;
}
//按评分降序排序
BOOL compareScoreByDescending(Teacher teacher1, Teacher teacher2) {
    if (teacher1.score < teacher2.score) {
        return YES;
    }
    return NO;
}
//输出全部男老师
void printMaleTeacher(Teacher *teachers, int count) {
    for (int i = 0; i < count; i++) {
        if (teachers[i].gender == 'm') {
            printf("Name:%-20sGender:%-20cAge:%-20dNumber:%-20dScore:%-20f\n", teachers[i].name, teachers[i].gender, teachers[i].age, teachers[i].number, teachers[i].score);
        }
    }
}
//输出全部女老师
void printFemaleTeacher(Teacher *teachers, int count) {
    for (int i = 0; i < count; i++) {
        if (teachers[i].gender == 'f') {
            printf("Name:%-20sGender:%-20cAge:%-20dNumber:%-20dScore:%-20f\n", teachers[i].name, teachers[i].gender, teachers[i].age, teachers[i].number, teachers[i].score);
        }
    }
}
//声明一个枚举和用户从控制台输入的功能数字对应
typedef enum FunctionName List;
//打印操作说明
void printInstructions() {
    printf("输入1:实现按照姓名进行升序排序\n");
    printf("输入2:实现按照姓名进行降序排序\n");
    printf("输入3:实现按照员工编号进行升序排序\n");
    printf("输入4:实现按照员工编号进行降序排序\n");
    printf("输入5:实现按照评分进行升序排序\n");
    printf("输入6:实现按照评分进行降序排序\n");
    printf("输入7:实现输出所有的男老师\n");
    printf("输入8:实现输出所有的女老师\n");
    printf("=================================\n");
    printf("请输入实现功能对应的数字:");
}

函数调用


main.m

//创建Teacher类型的结构体数组
Teacher teachers[] = {
    {"CLS", 'f', 35, 120, 100.0},
    {"XQC", 'f', 32, 100, 98.5},
    {"CGX", 'm', 36, 110, 99.5},
    {"XDL", 'f', 30, 90, 59.5},
    {"ZSY", 'm', 24, 190, 60.0}
};
int main(int argc, const char * argv[]) {
    //定义变量
    CompareFunctionPointer function = NULL;
    int n = 0;
    BOOL isAgain = YES;
    int count = sizeof(teachers) / sizeof(teachers[0]);
    //输出用户操作说明
    printInstructions();
    while (isAgain) {
        function = NULL;
        scanf("%d", &n);
        switch (n) {
            case CompareNameByAscending:
                function = compareNameByAscending;
                break;
            case CompareNameByDescending:
                function = compareNameByDescending;
                break;
            case CompareNumberByAscending:
                function = compareNumberByAscending;
                break;
            case CompareNumberByDescending:
                function = compareNumberByDescending;
                break;
            case CompareScoreByAscending:
                function = compareScoreByAscending;
                break;
            case CompareScoreByDescending:
                function = compareScoreByDescending;
                break;
            case PrintFemaleTeacher:
                printFemaleTeacher(teachers, count);
                break;
            case PrintMaleTeacher:
                printMaleTeacher(teachers, count);
                break;
            default: {
                printf("对不起您输入的数字没有对应的函数,请重新输入:");
                break;
            }
        }
        if (function != NULL) {
            sortTeachers(teachers, count, function);
            printTeachers(teachers, count);
        }
    }
    return 0;
}

案例分析

博主手把手教你玩转回调函数


  • 拿到一个案例,博主首先想到的是通过需求分析来设计一个程序的整体架构,尽可能将程序拆分为几个独立的模块,并提高程序的内聚性,减少程序的耦合性。接下来博主将通过对本案例尽可能详细的分析来说明这一点。
  • 首先我们先放下回调函数不管,按照由整体到局部来对这一案例进行分析,题目要求是创建一个结构体数组并且按照一定的顺序输出,那我们就可以先声明一个结构体,并且写一个函数,用来输出结构体数组的每一个成员的变量。这里楼主使用了typedef对结构体重命名,不懂的童鞋自行脑补,内事问度娘。
  • 第一步我们做完了,题目的要求是输出排序后的信息,我们可以写一个函数对数组进行排序。我们就先做一个按照评分对老湿们进行排序吧,之前都是老湿们给我们排序,现在换做我们给老湿们排序了,想想都暗爽那!闲话少叙,使用冒泡排序,对结构体数组按照比较部分交换整体的思想进行交换。
     for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if ((teacher[j].score - teacher[j + 1].score) > 0) {
                Teacher temp = teacher[j];
                teacher[j] = teacher[j + 1];
                teacher[j + 1] = temp;
            }
        }
    }
  • 看到这里有人要说了,既然这都已经可以实现了,为什么还要使用函数回调来做?这个问题问得好!如果只按照一种规则对结构体数组排序,确实这样就已经实现了,但题目是要求按照几种方式对老湿门进行排序,这时使用函数回调就能体现其优越性了。通过分析题目,改变排序规则改变的就是冒泡排序中的if判断条件,那么如果我们能将判断条件作为一个参数传入函数的话,就可以通过在主调函数中改变排序的条件。
    (teacher[j].score - teacher[j + 1].score) > 0
  • 按照这个思路继续想,怎样能将一个判断条件作为函数的参数传入到该函数中那?博主告诉你,回调函数就可以实现这个神奇的功能。有的看客们又要问,为什么回调函数可以作为函数参数那?这个问题问得妙,首先函数是存储在内存中一块叫做代码区的空间的,函数就存储在这块区域,并且每个函数都有一个地址,也就是指针,如果能得到这个地址的话,就可以通过调用定义指针变量指向该地址并调用该函数。
    函数名代表函数首地址,这例子代表定义一个返回值是int型并且有2个int型参数的函数指针p指向fun函数。
    int (*p)(int a, int b) = fun;
  • 首先需要定义一个返回值是BOOL类型并且有两个Teacher结构体变量的函数
    BOOL isTrue(Teacher teacher1, Teacher teacher2);
    为了让函数指针作为参数,需要定义一个相同类型的函数指针类型
    typedef BOOL(*CompareFunctionPointer)(Teacher teacher1, Teacher teacher2);
    看到了吧,有了两个结构体参数teacher1和teacher2就可以尽情的对老湿们进行各种方式的排序了。
  • 接下来定义几个CompareFunctionPointer类型的函数用来实现不同的排序,博主写了按照6中方式排序,看客们可以再自行编写对年龄的排序函数。
    void sortTeachers(Teacher teacher[], int count, CompareFunctionPointer cfp);
    根据博主的提示,相信大家都能完成这样一个排序的函数,其中的cfp就是我们讲到的函数指针,在函数实现部分也会很简单,还记得上面提到的冒泡排序嘛,只要在if的括号中调用函数cfp(teacher[j], teacher[j + 1])
  • 好了,万事俱备,接下来就要见证奇迹了,回到主调函数main.m中,先传入一个按照名字升序排序的函数并打印。注意函数指针参数,博主传入的是一个函数名字,而且没有括号和参数哦,原因上面已经说过了,函数名就是函数的地址,也叫做函数指针。输出结果就是按照名字升序排序的老湿信息。
int count = sizeof(teachers) / sizeof(teachers[0]);
printInstructions();
sortTeachers(teachers, count, compareNameByAscending);
printTeachers(teachers, count);

按姓名升序

  • 亲们看到这里不知道你们理解了没有,小编答应说要尽量详尽的带着大家学习函数回调,那就再带着大家来总结一下吧。
    1.函数回调适用范围:这个东西是一个比普通函数更有逼格的函数,但亲们也要分析具体案例决定使用与否。一般情况下回调函数可以用来替换在函数中的表达式中,达到动态改变条件的作用。
    2.函数回调的使用步骤:首先找到要替换的表达式,写出替换的函数并实现,并定义一个相同类型的函数指针类型,在原函数中加入函数指针类型参数,用回调函数替换原函数表达式部分。

博主讲到这里函数回调部分的内容就差不多结束了,本题目中要求输入功能对应数字并打印,那能不能通过输入一个字符串来调用对应的函数那?博主先卖个关子,看客们可以自行实现输入一个运算单词,例如:sum,max,minGB实现和函数的匹配,博主将在下一篇博客中和亲们分享:返回值是函数指针的函数。亲们记得关注哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值