用函数指针设置顺序
可能你已经猜到了答案:C标准库的排序函数会接收一个比较器函数(comparator function)指针,用来判断两条数据是大于、小于还是等于。
qsort()
函数看起来像这样:
qsort()
函数会反复比较两个数据的大小,如果顺序颠倒,计算机会交换它们。
这就是为什么要使用比较器函数。它会告诉qsort()
两个元素哪个排在前面,它会返回三种值:
下面来看一个例子,看看比较器函数在实际情况中是如何工作的。
int排序聚焦
假设有一个整型数组,你想升序排列它们,比较器函数应该长什么样子?
- int scores[] = {543,323,32,554,11,3,112};
你观察
qsort()
接收的比较器函数的签名,会发现它接收两个void*
,也就是两个void指针。我们在使用malloc()时碰到过它,void指针可以保存任何类型数据的地址,但使用前必须把它转换为具体类型。
qsort()
函数会两两比较数组元素,然后以正确的顺序排列它们。qsort()
通过调用传给它的比较器函数来比较两个元素的大小。
- int compare_scores(const void score_a, const void score_b)
- {
- …
- }
值以指针的形式传给函数,因此要做的第一件事就是从指针中提取整型值。
如果
a
大于b
,需要返回正数;如果a
小于b
,就返回负数;如果相等,返回0值。对整型来讲这很简单,只要将两数相减就行了:
下面是用
qsort()
排序这个数组的方法:
- qsort(scores, 7, sizeof(int), compare_scores);
练习
现在轮到你了,下面描述了几种不同的排序,你能为每种排序编写比较器函数吗?为了帮你,第一个比较器函数已经写好了。
最后,假设你已经有了
compare_areas()
和compare_names()
,下面两个比较器函数你会怎么写?
练习解答
现在轮到你了,下面描述了几种不同的排序。请为每种排序编写比较器函数。
最后,在已经有了
compare_areas()
和compare_names()
的前提下,下面两个比较器函数你会怎么写?
轻松一刻
即使你被这题难倒了也不用担心。
本题涉及指针、函数指针,甚至还有一些数学,如果你觉得很难,那就休息一下,喝两口水,过一两小时以后再来试试。
试驾
有几个比较器函数确实比较难写,有必要运行一下。需要用以下代码调用比较器函数。
编译并运行代码,将得到:
太棒了,代码工作了!
现在试着写一些你自己的代码吧。排序函数很有用,比较器函数却很难写,不过熟能生巧,多写几个就会了。
这里没有蠢问题
问:用来给字符串数组排序的比较器函数使用了
char**
,它是什么意思?答:字符串数组中的每一项都是字符指针(
char*
),当qsort()
调用比较器函数时,会发送两个指向数组元素的指针,也就是说比较器函数接收到的是指向字符指针的指针,在C语言中就是char**
。问:当调用
strcmp()
时,为什么是strcmp(*a, *b)
而不是strcmp(a, b)
?答:
a
、b
的类型是char**
,而strcmp()
函数需要接收char*
类型的值。问:
qsort()
会创建新数组吗?答:不会,
qsort()
在原数组上进行改动。问:为什么我的头有点疼?
答:别担心,指针很难用,如果你一点儿也不感到困扰,可能是想得还不够深。