从零开始的C语言学习014 指针5
1.回调函数
回调函数是⼀个通过函数指针调用的函数。
把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。
什么意思呢?
简单来说就是需要用到该函数的时候不直接调用,而是通过另外一个函数来调用,这样就被称之为回调函数。
(以下是回调函数的转移表)
#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
void calc(int(*pf)(int, int))
{int ret = 0;int x, y;printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}int main(){int input = 1;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");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;}
我们这里重点说一下这个函数:
这个函数是什么意思?
void calc(int(*pf)(int, int))
那这样呢?
int(*pf)(int,int)
显然这是一个函数指针,接受一个地址,返回一个int类型的值。
这里的pf可以是任何符合形式的函数,只需要接受对应的函数地址即可使用。
那整体来说。calc就需要传一个函数地址。
而这里的calc(add)便是接受了函数add的地址。pf便成为了有加法作用的函数。
2.qsort函数使用
qsort是一个库函数,但和可以直接使用的库函数不同,qsort函数需要使用者自己去定义一个比较函数。
这里我们可以先看一下qsort函数的定义:
(这里其实应该是nitems,但显然count大家都学过)
void qsort(void *base, size_t count, size_t size, int (*compar)(const void *, const void *));
比较函数是用户自定义的,用于确定两个元素的相对顺序:
int (*compar)(const void *, const void *)
至于其他的则已经编译完成,只需要填上对应的:
-
base: 指向待排序数组的起始地址。
-
count: 数组中元素的个数。
-
size: 每个元素的大小(以字节为单位)
为什么比较函数需要使用者自己定义,而不是编译器帮你定义呢?
因为这两个元素不一定是数字。
如果是数字的话,只需要加或者减即可,但这个比较的范围扩大到字符就无法比较了。
这里我们先给出如何比较数字:
#include <stdio.h>
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);return 0;
}
而如何比较字符/字符串呢?
我们可以想到之前的字符串比较函数:strcmp
这样其实就非常简单了,不多赘述。
3.qsort函数的实现
实现一个项目之前永远要想想看它的功能是什么。
qsort便是比较函数并排序。
那怎么比较?怎么排序?
会接受什么类型?用什么类型去接受并比较?
想明白的话我们便可以用冒泡排序的思维去解决,不过是将int类型改为char类型。
#include <stdio.h>
void _swap(void* p1, void* p2, size_t 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, size_t count, size_t 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);}}}
}
这里的cmp便是需要使用者自己手写的地方。