想法:列表列表(针对发布者订阅问题)
问题是:列表使用不同类型的结构作为节点。因此,我的函数不能与第二种类型的结构一起工作(这很好,我可以简单地创建另一个函数并更改它使用的参数)。
但我觉得这是一个相当简单的方法,老实说,我需要处理的代码量有点太多了。
有没有更专业/更有经验的方法来做到这一点?(我能应付。例如,他们在这里谈论它,但我不确定我是否可以在不弄乱它的情况下实现它,因为我从未使用过工会:
How to Pop different types of Structs from a Stack
)
这是一种常见的/可接受的方式吗(为不同的结构/数据类型重用函数)?
我使用的结构:

struct nodoTemas{
    char * nombreTema;
    struct nodoSuscriptor * nodoCerodeSuscriptores;
    struct nodoTemas * next;
};

struct nodoSuscriptor{
    char * nombreSuscriptor;
    //int iP;
    struct nodoTemas * next;
};

因此,我有一个工作代码,其中包含一个创建列表的函数,以及其他与之交互的类似方法。
struct nodoTemas* create_list(char * val, struct nodoTemas * head, struct nodoTemas *curr)
 {
     printf("\n creating list with headnode as [%s]\n",val);
     struct nodoTemas *ptr = (struct nodoTemas*)malloc(sizeof(struct nodoTemas));
if(NULL == ptr)
{
    printf("\n Node creation failed \n");
   return NULL;
}
ptr->nombreTema = val;
ptr->next = NULL;

head = curr = ptr;
printf("Ha llegado aqui3\n");
return ptr;
 }

我提供了这么多代码,因为我通常被要求这样做。如往常一样,如果这个地方不对/这个问题措词不当,我很抱歉。
编辑:我现在发现使用union和struct,它可以容纳两个或更多类型中最大的一个。我不确定这是否只是浪费了太多的空间,从而使这成为一个不太好的选择,所以也不太确定如何做到这一点(想法是,如果它是一个suscriber列表,那么它可能是2或2000,并且随着每个节点的添加,会有浪费的空间)。

最佳答案

您正在努力解决的问题——如何创建可重用的通用功能,如容器——是一个容易用面向对象的编程语言(如C++)解决的问题。然而,它们可以在C中实现,即使不是那么容易和灵活。
关键是确定哪些功能是通用的,哪些是特定于列表中节点类型的。
一般功能包括创建/初始化列表、添加节点、删除节点、遍历列表等功能。
创建用于处理列表的独立函数,以及一个对泛型节点建模的结构。
然后,创建表示列表中不同对象类型的结构。在每个结构中嵌入一个通用列表节点结构作为第一个元素,并根据需要编写函数,以提供处理需要处理的每种不同类型对象的功能。
这样,您就得到了通用的、可重用的列表,而且作为额外的好处,您可以保持处理特定对象类型的代码干净且易于维护。
下面是一个简单的程序来演示这个原理。它允许创建表示苹果和桔子的对象列表。苹果有跟踪重量的功能,橘子有跟踪价格的功能。

#include <stdio.h>
#include <stdlib.h>

/* First we start with the definition of a generic list node */

struct list_node {
    struct list_node *next;
    struct list_node *prev;

    /* The 'type' field is important - it allows us to have a list
     * containing a number of different types of node, and to be able
     * to find out what type each node is */
    int type;
};

/* Some variables to keep track of the beginning and end of the list. */

struct list_node* head;
struct list_node* tail;

/* Now some generic functions for dealing with lists - initializing the list,
 * adding nodes through it, iterating through the list */

void list_init() {
    head=tail=NULL;
}

void list_add_node(struct list_node* node) {
    if (NULL==tail) {
        head=tail=node;
        node->next=NULL;
        node->prev=NULL;
    } else {
        tail->next=node;
        node->next=NULL;
        node->prev=tail;
        tail=node;
    }
}

struct list_node* list_get_next(struct list_node* node) {
    if (NULL==node)
        return head;
    else
        return node->next;
};

/* Great, now we have a generic set of functions for dealing with generic lists.
 * But how do we use that to contain different kinds of objects? The answer
 * is composition - we include the list_node as the first element of each of the
 * structs that we want to add to the list
 *
 *
 * Here we define a struct for recording the weight of apples, together with
 * functions specific to dealing with apples
 */

struct apple {
    struct list_node node;
    int weight;
};

struct apple* new_apple(int weight) {
    struct apple* a = (struct apple*)malloc(sizeof(struct apple));
    /* Apples are considered type 1 */
    a->node.type = 1;
    a->weight = weight;
    return a;
};

void apple_printweight(struct apple* a) {
    printf("This is an apple and it weighs %d grams\n", a->weight);
}

/* And here we define a struct for recording the price of oranges, together with
 * functions specific for dealing with oranges
 */

struct orange {
    struct list_node node;
    double price;
};

struct orange* new_orange(double price) {
    struct orange* o = (struct orange*)malloc(sizeof(struct orange));
    /* Oranges are type 2 */
    o->node.type = 2;
    o->price=price;
    return o;
};

void orange_printprice(struct orange* o) {
    printf("This is an orange and it costs $%6.2f dollars\n", o->price);
}

/* Now to use our oranges and apples */

int main() {

    list_init();

    /* Create an orange, add it to the list
     *
     * Note the need to cast the orange to a list_node
     * so we can call the 'list_add_node' function.
     * This makes use of a property of pointers to structs:
     * you can always convert them to point to the first element of
     * the struct.
     */
    struct orange* myOrange = new_orange(12.50);
    list_add_node((struct list_node*)myOrange);

    /* Create an apple, add it to the list */
    struct apple* myApple = new_apple(150);
    list_add_node((struct list_node*)myApple);

    /* Iterate through the list */
    struct list_node* n = NULL;
    while (n = list_get_next(n)) {

        /* For each node we come to, it could be an apple or an orange.
         * Inspect the type to find out what type it is, and use it
         * accordingly */
        if (n->type == 1) {
            apple_printweight((struct apple*)n);
        } else if (n->type == 2) {
            orange_printprice((struct orange*)n);
        }
    }

    /* In a real program you would want to free the list objects here
     * to avoid a memory leak
     */

}

输出如下:
This is an orange and it costs $ 12.50 dollars
This is an apple and it weighs 150 grams

请记住,这只是一个简单的例子,绝不能说明所有方面的最佳实践。在现实生活中,您可以将声明分成头文件,并且您可能会做一些比主循环中的if/then分支更优雅的事情来处理不同的类型。

10-05 18:29
查看更多