2016-09-18 31 views
2

我试图在C. 写链表在通用搜索功能的功能如下:在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; 
} 

基本上条件是一个函数指针,这将针对每个元件进行测试的功能的链表,并且只要这个函数返回true就返回特定的节点。

我的链表中的每个节点都存储一些ID。我的问题是,如果我不想搜索特定的ID,则必须编写一个单独的搜索功能,该功能只能检查该特定的ID。基本上,如果我wan't找ID 10.我必须写一个函数

​​

如果我想测试一些其他的ID说30,我会写一个不同的功能again..I认为你明白了我的观点。

我只能想到currying来解决这个问题..但不幸的是C不提供currying,我不能使用一些编译器特定的解决方法,因为我的代码应该在所有平台上编译。

使用全局变量作为搜索ID是一种解决方案,但我不想避免它。

如何解决这个问题?

+0

但明天,如果我用我的链表存储一些结构,整数和字符,我想比较它们都那么结构格式将发生变化并且我的get_when_true函数将不会保持通用 – Nullpointer

回答

3

您应该向传递给您的回调的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函数,以便它们自动在那里可用。

参见:

+0

是的..这看起来是一个不错的选择!谢谢 – Nullpointer

+1

谢谢,提及关闭与void指针的关系! – Nullpointer

+1

不客气。我花了很长时间才意识到两者是直接相关的。使用GCC的嵌套函数查看我的附加示例。 –