【问题标题】:How can I reduce code repetition in my C code (unsure due to null pointers)如何减少 C 代码中的代码重复(由于空指针而不确定)
【发布时间】:2025-12-05 16:05:02
【问题描述】:

在我的项目中,我链接了struct elem 的链接,每个元素都有许多不同的属性。

目前每次我想获取一个elems属性,我都会调用一个函数比如:

     get_elem_address(&linked_list);
     get_elem_this(&linked_list);
     get_elem_that(&linked_list);

在每个函数中我都有相同的代码:

struct elem *elem = linked_list->first_elem;

while (elem != NULL) {
    if (elem->identifer == identifer) get_elem_whatever_i_need;
    elem = elm->next;
}

在某些函数中,我可以保证会有一个标识符匹配的元素,在其他函数中我不确定。有没有办法可以编写一个函数来遍历链表并找到我想要的元素然后返回它。

我不确定我是否可以这样做的原因是因为它可能不是一个与传入的标识符具有相同标识符的元素。

【问题讨论】:

    标签: c linked-list implementation redundancy abstract-data-type


    【解决方案1】:

    这个答案可能会得到很多来自传统 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);
    }
    

    您是否对这种方法感到满意当然取决于您,但对我来说,它已成为一种标准工​​具。

    【讨论】: