想法:列表列表(针对发布者订阅问题)
问题是:列表使用不同类型的结构作为节点。因此,我的函数不能与第二种类型的结构一起工作(这很好,我可以简单地创建另一个函数并更改它使用的参数)。
但我觉得这是一个相当简单的方法,老实说,我需要处理的代码量有点太多了。
有没有更专业/更有经验的方法来做到这一点?(我能应付。例如,他们在这里谈论它,但我不确定我是否可以在不弄乱它的情况下实现它,因为我从未使用过工会:
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分支更优雅的事情来处理不同的类型。