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

问题描述 投票:2回答:2

[第一次问一个问题,但我确实环顾了Google和stackoverflow,看看以前是否有人问过类似的问题。例如,在malloc, recasting and 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 *指针,因此我对上述代码的实验效果不佳。

c list casting traversal
2个回答
2
投票

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

struct list_item {
    struct list_item *next;
    enum 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


0
投票

如果确保下一个指针是该结构的第一个成员,则可以这样做。

typedef struct list1 {
    // next pointer must be first
    struct list1 *next;
    int value;
} list1;

typedef struct list2 {
    // next pointer must be first
    struct list2 *next;
    int value;
    char *string;
} list2;

void freeList(void *list) {
    if (list) {
        freeList(*(void**)list);
        free(list);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.