在 C 中为链表编写通用搜索函数?
Posted
技术标签:
【中文标题】在 C 中为链表编写通用搜索函数?【英文标题】:Writing generic Search function for linked list in C? 【发布时间】:2016-09-18 15:11:02 【问题描述】:我正在尝试在 C 中的链表上编写通用搜索函数。 函数如下:
void* get_when_true(linked_list *l,
int (*condition)(const void*))
node **walk = &l->head;
while (*walk != NULL && !condition((*walk)->data))
walk = &((*walk)->next);
return (*walk)->data;
condition 基本上是一个函数指针,指向一个函数,该函数将针对链表的每个元素进行测试,并且只要该函数返回 true,就会返回特定节点。
我的链表中的每个节点都存储了一些 ID。我的问题是,如果我不想搜索特定 ID,我必须编写一个单独的搜索函数,该函数只能检查该特定 ID。基本上如果我不想查找 ID 10。我必须编写一个函数
int isID_10(const void *a)
// cast A to appropriate poitner
return a->ID == 10;
如果我想测试其他 ID,比如 30,我将不得不再次编写不同的函数。我想你明白了。
我只能想到用柯里化来解决这个问题。但不幸的是,C 不提供柯里化,而且我不能使用一些特定于编译器的变通方法,因为我的代码应该在所有平台上编译。
使用全局变量作为搜索 ID 是一种解决方案,但我不想避免。
如何解决这个问题?
【问题讨论】:
但是明天如果我使用我的链表来存储一些结构、整数和字符并且我想比较它们,那么结构格式将会改变,我的 get_when_true 函数将不再保持通用 【参考方案1】:您应该向get_when_true
添加另一个参数,该参数将传递给您的回调。这可以只是另一个void *
,因此它可以指向任何类型的结构。
void* get_when_true(linked_list *l, void *ctx,
int (*condition)(const void* data, void *ctx))
node **walk = &l->head;
while (*walk != NULL && !condition((*walk)->data, ctx))
walk = &((*walk)->next);
return (*walk)->data;
这是一个回调:
int isID(const void *data, void *ctx)
int id = (int)ctx;
const struct whatever *a = data;
return a->ID == id;
这样使用:
get_when_true(list, (void*)10, isID);
在这里,我什至不需要结构,所以我“作弊”,只是将单个整数转换为 void*
。
由于 C 本身不支持闭包,其中有数据“附加”到(回调)函数指针,所以我编写的任何接受回调的函数也需要传递给回调的 void*
。
虽然 C 不支持闭包,但有一个 GNU 扩展提供嵌套函数,可以访问父函数范围内的变量。因此,使用您的原始代码(没有我的附加参数):
int get_when_id(linked_list *l, int id)
int condition(const void *data)
const struct whatever *a = data;
return a->ID == id; // id is "closed over" from parent
return get_when_true(list, condition);
这需要一个可执行堆栈。如果你看一下反汇编,你会发现实际上传递给get_when_true
的函数指针并不是condition
本身的地址。相反,一个可执行文件的地址 thunk 是在堆栈上生成并传递的。这个 thunk 将一个指向封闭变量的指针传递给实际的 condition
函数,因此它们会自动在那里可用。
另见:
Is there a a way to achieve closures in C【讨论】:
谢谢你提到闭包和空指针的关系! 不客气。我花了很长时间才意识到这两者是直接相关的。请参阅我使用 GCC 的嵌套函数的附加示例。 我不能推荐 GCC 的嵌套函数。其他一切都加一个;减一——净零。以上是关于在 C 中为链表编写通用搜索函数?的主要内容,如果未能解决你的问题,请参考以下文章