1.回调函数
回调函数是通过函数指针调用的函数
将函数指针作为参数传递给另一个函数,当这个函数指针被用来调用其所指向的函数时,被调用的函数就是回调函数,回调函数不是应该由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行响应
//改造前-无回调函数
int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
void menu()
{printf("****************************\n");printf("***** 1.add 2.sub ******\n");printf("***** 3.mul 4.div ******\n");printf("***** 0.exit ******\n");printf("****************************\n");}int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Add(x, y);printf("%d\n", ret);break;case 2:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("%d\n", ret);break;case 3:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("%d\n", ret);break;case 4:printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = Div(x, y);printf("%d\n", ret);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}
//改造后-有回调函数
int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
void menu()
{printf("****************************\n");printf("***** 1.add 2.sub ******\n");printf("***** 3.mul 4.div ******\n");printf("***** 0.exit ******\n");printf("****************************\n");}
void calc(int(*pf)(int, int))
{int x = 0;int y = 0;int ret = 0;printf("请输入两个操作数:>");scanf("%d %d", &x, &y);ret = pf(x, y);printf("%d\n", ret);
}
int main()
{int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:calc(Add);break;case 2:calc(Sub);break;case 3:calc(Mul);break;case 4:calc(Div);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}
解释:只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么函数,这⾥其实使⽤的就是回调函数的功能,可以避免一些代码的冗余。
2.qsort使用
语法
void qsort(void* base,//base指向待排序的第一个元素size_t num,//待排序个数size_t size,//待排序的数组元素的大小,单位字节int(*compar)(const void*, const void*)//compar是函数指针,指向函数能比较两个元素
);
//4个参数
//void*是一种指针类型
#include<stdlib.h>
#include <stdio.h>
//qosrt函数的使⽤者得实现⼀个⽐较函数
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}
运行结果
解释:qsort的参数分别是,待排序数组,数组元素的个数,每个元素大小,比较函数。通过比较函数进行比较,将两个指向常量类型的指针,转换成整形指针解引用,返回差值,如果第一个元素小于第二个元素,返回负数,相等返回0,大于返回正数
3.qsort函数模拟实现
使用回调函数,模拟实现qsort, 采用冒泡方式
#include <stdio.h>
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)
{int i = 0;for (i = 0; i< size; i++){char tmp = *((char *)p1 + i);*(( char *)p1 + i) = *((char *) p2 + i);*(( char *)p2 + i) = tmp;}
}
void bubble(void *base, int count , int size, int(*cmp )(void *, void *))
{int i = 0;int j = 0;for (i = 0; i< count - 1; i++){for (j = 0; j<count-i-1; j++){if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0){_swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}
运行结果
解释:bubble函数参数分别是待排序数组,数组元素个数,每个元素大小,比较函数
调用bubble, 比较相邻元素大小随着外层循环排序次数的减小,内层循环的待比较元素向后移动进行比较,比较整型数时调用int_cmp函数,返回差值,小于0,第一个元素小于第二个元素,等于0相等,大于0,第一个元素大于第二个元素,当返回值大于0时,调用交换函数_swap进行交换,该函数可以处理任何类型的数据,通过遍历每个字节,进行交换