C语言中通用数据结构实现的最佳实践

时间:2019-04-07 15:45:12

标签: c data-structures avl-tree

在我用C实现通用数据结构的冒险中,我遇到了一个难题。例如,在以下代码中:

void add_something(avl_tree_t * my_tree) {
        int new_element = 123;

        avl_insert(my_tree, (void*)&new_element);
}

int main() {
        avl_tree_t * my_tree = avl_create();

        add_something(my_tree);

        // do stuff

        avl_print(my_tree, function_that_prints_ints);

        exit(0);
}

其中avl_insert被定义为

void avl_insert(avl_tree_t * tree, void * data) {
        avl_node_t * new_node = malloc(sizeof(struct avl_node));

        new_node->data = data;
        // do tree balancing stuff
}

为了使我的通用插入功能正常工作,我必须向其传递一个void *项以进行存储。但是,为了使其正常工作,在这种情况下,我需要传递我要添加的新int项的地址,以便随后将其取消引用到void *。如果我没记错的话,当我们回到main函数时,存储新元素的内存地址将受到损害。

解决这个问题的一种方法是传递存储在树中的内容的大小作为avl_create的参数,然后为插入的每个元素的副本分配内存。之所以可行,是因为您不需要添加任何原始地址或值。

另一种可行的方法是仅在单个函数的范围内使用数据结构,这显然不可行。

我的问题是这样的:在基本数据类型或用户创建的结构中,将静态分配的数据存储在通用数据结构中的最佳方法是什么?

谢谢。

2 个答案:

答案 0 :(得分:1)

要使用自动存储持续时间存储指向数据的指针,是的,您将必须知道容器中元素的大小,并分配和复制指向的数据。

最简单的方法是仅在所有情况下分配和复制,如有必要,可以选择使用用户指定的clone()create()函数进行深拷贝。这还需要使用用户指定的destroy()函数来正确处理副本(必要时再次)。

要避免分配,您必须具有某种状态变量,让您知道容器是否应该分配,或者只是复制指针值本身。

请注意,这应适用于容器对象,而不适用于各个节点或元素。如果容器以一种或另一种方式存储数据,则应以该方式存储所有数据。参见Principle of Least Astonishment

这是更复杂的方法,因为您必须确保使用正确的过程基于状态变量添加和删除元素。通常,只需确保您永远不会传递指向具有自动存储持续时间的值的指针,就容易得多。

答案 1 :(得分:1)

使用混合样式;例如不要将数据作为节点的一部分,而是将节点作为数据的一部分:

struct avl_node {
    struct avl_node *parent;
    struct avl_node *left;
    struct avl_node *right;
};

struct person {
    char const *name;
    struct avl_node node;
};

struct animal {
    struct avl_node node;
    int dangerousness;
};

animal的构造函数就像

struct animal *animal_create(double d)
{
    struct animal *animal = malloc(sizeof *animal);

    *animal = (struct animal) {
        .node = AVL_NODE_INIT(),
        .dangerousness = d,
    };

    return animal;
}

通用的AVL树操作看起来像

void avl_tree_insert(struct avl_node **root, struct avl_node *node, 
                     int (*cmp)(struct avl_node const *a, struct avl_node const *b))
{
    /* .... */
}

cmp的{​​{1}}函数,如

animal