首页 > 解决方案 > 只要它们包含“下一个”字段,是否可以在 C 中为不同的列表结构编写通用遍历函数?

问题描述

第一次问问题,但我确实环顾了谷歌和 stackoverflow,看看是否有人以前问过类似的问题。在malloc、recasting 和 free中,看起来 OP 提出了类似的问题。但情况更复杂。

我想知道是否可以在 C 中为遍历列表的列表结构创建一个通用函数,因为您知道不同类型的结构将始终具有“下一个”字段。

例如,给定这两个列表类型结构:

typedef struct _list1 {
    int value;
    list1 *next;
} list1;

typedef struct _list2 {
    int value;
    char *string;
    list2 *next;
} list2;

是否可以创建一个通用void freeList((void *) list)函数或类似下面的东西?我知道为每个单独的列表分别编写两个免费函数是一件简单的事情。

void freeList((void *) list) {
    // Included this because the structs would have different sizes
    // so I thought it would be possible to cast it in order to properly dereference the field.
    if (sizeof *list == sizeof list1)
        *list = (list1) list;
    else if (sizeof *list == sizeof list2)
        *list = (list2) list;

    if (!list) return;
    else {
        free(list->next);
        free(list);
    }
}

到目前为止,我对上面显示的代码的实验并不顺利,因为 gcc 会抱怨取消引用void *指针。

标签: clistcastingtraversal

解决方案


制作一个异构列表可以通过使用标记的联合来实现,或者只是一个标记和强制转换:

struct list_item {
    struct list_item *next;
    enum datatype type;
    void *contents;
};

或者

struct list_item {
    struct list_item *next;
    enum datatype type;
    union {
       int some_int;
       char some_char;
    } contents;
};

然后在遍历列表时,您只需type在使用元素的内容之前验证存储的类型。


本次检查:

if (sizeof *list == sizeof list1)
    *list = (list1) list;
else if (sizeof *list == sizeof list2)
    *list = (list2) list;

不起作用,因为sizeof它是一个静态构造:它的值是在编译时定义的。你只是要求sizeof void.


推荐阅读