这个答案可能会得到很多来自传统 C 编程社区的 cmet,也不太可能得到很多反对票,但我仍然会给出它。
您可以考虑使用函数式编程方法。对于一个简单的链表,它可以说是矫枉过正,我个人(也)会坚持你给的循环,但在更复杂的数据结构上,它绝对值得考虑。链表确实是一个很好的演示。
假设我们有以下链表:
#include <string.h>
typedef struct elem
{
struct elem * next;
char * identifier;
} t_elem;
那么我们可以编写一个通用的finder函数如下:
t_elem * find(t_elem * list, int (*sel)(t_elem * elem))
{
for (; list != NULL; list = list->next)
if (sel(list))
{
break;
}
return list;
}
它将选择函数作为参数,在 C 编程中通常称为 回调,并返回该函数返回非零的列表中的第一个元素。查找具有特定标识符的第一个元素可能如下所示:
t_elem * find_id(t_elem * list, char * id)
{
int sel(t_elem * e)
{
return strcmp(e->identifier, id) == 0;
}
return find(list, sel);
}
上面的函数是非标准的 ANSI,因为它使用了一个嵌套函数。 GCC 支持这一点,出于这个原因,我会鼓励标准化委员会采用这种嵌套函数。
如果您想要或必须坚持标准的 ANSI,那么您将必须明确所谓的 closure,就像我在以下示例中所做的那样。在这种情况下,闭包只包含参数id,但通常必须定义专用的struct。闭包作为void 指针传递,并在使用时转换为适当的类型(确实容易出错)。
t_elem * find2(t_elem * list, int (*sel)(t_elem * elem, void *), void * cl)
{
for (; list != NULL; list = list->next)
if (sel(list, cl))
{
break;
}
return list;
}
int sel_id(t_elem * e, void * cl)
{
char * id = cl;
return strcmp(e->identifier, id) == 0;
}
t_elem * find_id2(t_elem * list, char * id)
{
return find2(list, sel_id, id);
}
您是否对这种方法感到满意当然取决于您,但对我来说,它已成为一种标准工具。