这里有一个简单的函数,它用于在单链表中查找一个值。它的参数是一个指向链表第 1 个节点的指针以及那个需要查找的值。
Node *
search_list(Node *node, int const value)
{
while(node!=NULL){
if( node->value == value )
break;
node = node->link;
}
return node;
}
这个函数看上去相当简单,但它只适用于值为整数的链表。如果你需要在一个字符串链表中查找,你不得不另外编写一个函数。这个函数和上面那个函数的绝大部分代码相同,只是第 2 个参数的类型以及节点值的比较方法不同。
一种更为通用的方法是使查找函数与类型无关,这样它就能用于任何类型的值的链表。我们必须对函数的两个方面进行修改,使它与类型无关。
首先,我们必须改变比较的执行方式,这样函数就可以对任何类型的值进行比较。这个目标听上去好像不可能,如果你编写语句用于比较整型值,它怎么还可能用于其它类型如字符串的比较呢? 解决方案就是使用函数指针。调用者编写一个比较函数,用于比较两个值,然后把一个指向此函数的指针作为参数传递给查找函数。而后查找函数来执行比较。使用这种方法,任何类型的值都可以进行比较。
我们必须修改的第 2 个方面是向比较函数传递一个指向值的指针而不是值本身。比较函数有一个 void * 形参,用于接收这个参数。然后指向这个值的指针便传递给比较函数。(这个修改使字符串和数组对象也可以被使用。字符串和数组无法作为参数传递给函数,但指向它们的指针却可以。)
使用这种技巧的函数被称为回调函数(callback function),因为用户把一个函数指针作为参数传递其它函数,后者将”回调“用户的函数。任何时候,如果你所编写的函数必须能够在不同的时刻执行不同类型的工作或者执行只能由函数调用者定义的工作,你都可以使用这个技巧。
【提示】
在使用比较函数的指针之前,它们必须被强制转换为正确的类型。因为强制类型转换能够躲开一般的类型检查,所以你在使用时必须格外小心,确保函数参数类型是正确的。
在这个例子里,回调函数比较两个值。查找函数向比较函数传递两个指向需要进行比较的值的指针,并检查比较函数的返回值。例如:零表示相等的值,现在查找函数就与类型无关,因为它本身并不执行实际的比较。确实,调用者必须编写必需的比较函数,但这样做是很容易的,因为调用者知道链表中所包含的值的类型。如果使用几个分别包含不同类型值的链表,为每种类型编写一个比较函数就允许单个查找函数作用于所有类型的链表。
程序段01 是类型无关的查找函数的一种实现方法。 注意函数的第 3 个参数是一个函数指针。这个参数用一个完整的原型进行声明。同时注意虽然函数绝不会修改参数 node 所指向的任何节点,但 node 并未被声明为 const 。如果 node 被声明为 const,函数将不得不返回一个const结果,这将限制调用程序,它便无法修改查找函数所找到的节点。
/*
**程序 01 ——类型无关的链表查找函数
**在一个单链表中查找一个指定值的函数。它的参数是一个指向链表第 1 个节点的指针、一个指向我们需要 查找的值的指针和一个函数指针。
**它所指向的函数用于比较存储于链表中的类型的值。
*/
#include <stdio.h>
#include "node.h"
Node *
search_list( Node *node, void const *value, int (*compare)( void const *, void const *) )
{
while (node!=NULL){
if(compare(&node->value, value)==0)
break;
node=node->link;
}
return node;
}
指向值参数的指针和 &node->value 被传递给比较函数。后者是我们当前所检查的节点值。
在一个特定的链表中进行查找时,用户需要编写一个适当的比较函数,并把指向该函数的指针和指向需要查找的值的指针传递给查找函数下面是一个比较函数,它用于在一个整数链表中进行查找。
int
compare_ints( void const *a, void const *b )
{
if( *(int *)a == *(int *)b )
return 0;
else
return 1;
}
这个函数像下面这样使用:
desired_node = search_list ( root, &desired_value, compare_ints );
注意强制类型转换:比较函数的参数必须声明为 void * 以匹配查找函数的原型,然后它们再强制转换为 int * 类型,用于比较整型值。
如果你希望在一个字符串链表中进行查找,下面的代码可以完成这项任务:
#include <string.h>
...
desired_node = search_list( root, "desired_value", strcmp);
碰巧,库函数 strcmp 所执行的比较和我们需要的完全一样,不过有些编译器会发出警告信息,因为它的参数被声明为 char * 而不是
void *。
http://hi.baidu.com/_oov/blog/item/6571efb49dfc94728bd4b27b.html