- 函数指针数组
- 函数指针数组的用途:转移表
- 回调函数
- 用回调函数简化计算器
- 基于回调函数模拟实现qsort函数
- 演示qsort函数的使用
- 对一组整形数组进行升序排序
- 使用qsort来排升序结构数据
- 用冒泡排序模拟实现qsort函数
函数指针数组的用途:转移表函数指针数组是一个数组,数组元素是函数指针。
函数指针数组的形式:int (*parr[10])();
parr 先和[] 结合,说明 parr是数组,数组的内容是什么呢?
是 int(*)() 类型的函数指针。
例子写一个计算器:
要求:有加法,减法,乘法,除法。
我们以往的代码实现:
#includevoid menu() { printf("***************************n"); printf("****** 1.add 2.sub ******n"); printf("****** 3.mul 4.div ******n"); printf("****** 0.exit ******n"); printf("***************************n"); } 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; } int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); int x = 0; int y = 0; int ret = 0; switch (input) { case 1: printf("请输入两个操作数:>"); scanf("%d %d", &x, &y); ret = Add(x, y); printf("%dn", ret); break; case 2: printf("请输入两个操作数:>"); scanf("%d %d", &x, &y); ret = Sub(x, y); printf("%dn", ret); break; case 3: printf("请输入两个操作数:>"); scanf("%d %d", &x, &y); ret = Mul(x, y); printf("%dn", ret); break; case 4: printf("请输入两个操作数:>"); scanf("%d %d", &x, &y); ret = Div(x, y); printf("%dn", ret); break; case 0: printf("退出计算器n"); break; default: printf("选择错误n"); break; } } while (input != 0); return 0; }
发现上面的代码主函数部分过于累赘,有很多重复的部分。
每个case语句内蓝框都是重复的部分,那我们如何把这些重复的部分用函数指针数组来解决?
#include回调函数void menu() { printf("***************************n"); printf("****** 1.add 2.sub ******n"); printf("****** 3.mul 4.div ******n"); printf("****** 0.exit ******n"); printf("***************************n"); } 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; } int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); int x = 0; int y = 0; int ret = 0; int (*arr[5])(int, int) = { NULL, Add, Sub, Mul, Div }; if (input == 0) { printf("退出计算器n"); } else if(input>0&&input<5) { printf("请输入两个操作数:>"); scanf("%d %d", &x, &y); ret = arr[input](x, y); printf("%dn", ret); } else { printf("选择错误n"); } } while (input != 0); return 0; }
用回调函数简化计算器回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。
#include基于回调函数模拟实现qsort函数 演示qsort函数的使用void menu() { printf("***************************n"); printf("****** 1.add 2.sub ******n"); printf("****** 3.mul 4.div ******n"); printf("****** 0.exit ******n"); printf("***************************n"); } 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 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("%dn", ret); } int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 0: printf("退出计算器n"); break; case 1: calc(Add); break; case 2: calc(Sub); break; case 3: calc(Mul); break; case 4: calc(Div); break; default: printf("选择错误n"); break; } } while (input != 0); return 0; }
对一组整形数组进行升序排序qsort - 这个函数可以排序任意类型的数据
- void qsort(void* base,//你要排序的数据的起始位置
size_t num,//待排序的数据元素的个数
size_t width,//待排序的数据元素的大小(单位是字节)
int(* cmp)(const void* e1, const void* e2)//函数指针-比较函数
);—>MSDN搜索得到的。
头文件--
#include使用qsort来排升序结构数据#include int cmp_int(const void* e1, const void* e2) { return (*(int*)e1 - *(int*)e2); } int main() { int arr[] = { 10,9,8,7,6,5,4,3,2,1 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp_int); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
#include用冒泡排序模拟实现qsort函数#include int cmp_int(const void* e1, const void* e2) { return (*(int*)e1 - *(int*)e2); } struct Stu { char name[20]; int age; }; int cmp_stu_by_name(const void* e1, const void* e2)//比较name { return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name); } int cmp_stu_by_age(const void* e1, const void* e2)//比较age { return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age; } int main() { struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//对name升序 int i = 0; for (i = 0; i < sz; i++) { printf("%s %dn", s[i].name, s[i].age); } printf("n"); qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//对age升序 for (i = 0; i < sz; i++) { printf("%s %dn", s[i].name, s[i].age); } printf("n"); return 0; }
qsort函数本来是用快速排序来进行排序的,但是快速排序是在数据结构学习的,所以在C语言还未学习到数据结构时先用已经学过的冒泡排序来模拟。
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag = 1;//假设数组是排好序的
//一趟冒泡排序的过程
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (cmp((char*)base + j * width, (char*)base + (j+1) * width))
{
//交换
Swap((char*)base + j * width, (char*)base + (j+1) * width, width);
flag = 0;
}
}
if (flag == 1)//判断一次冒泡排序后是否进行交换,未进行交换则有序,退出循环
{
break;
}
}
}
这个模拟sqort函数中与以前冒泡排序函数不同的是(char*)base + j * width,和(char*)base + j * width是什么意思呢?为啥必须要强制转换为(char*)呢?
实现Swap函数
void Swap(char* buf1, char* buf2, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
++buf1;
++buf2;
}
}
该Swap函数第一个参数和第二个参数是需要交换两个数据的首地址。sz是需要交换的两个数据的大小。
对两个数据的每个字节的数据依次进行交换,最终完成两个数据的交换。
对上面的qsort函数的使用几个案例,qsort函数用bubble_sort函数代替可以依次验证模拟实现函数的准确性



