需求分析
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.函数回调的使用步骤:首先找到要替换的表达式,写出替换的函数并实现,并定义一个相同类型的函数指针类型,在原函数中加入函数指针类型参数,用回调函数替换原函数表达式部分。