typedef struct node_t {
int x;
struct node_t *next;
} *Node; /* <-- don't typedef pointers */
只需使用Node 而不是Node *,然后分配:
Node *node1 = malloc(sizeof(*node1));
为什么?在typedef 声明下方查看您的代码 100 行的人不会天生就知道 Node 是否是一个类型,或者它是否是一个指向类型的指针。这种类型的混淆只会随着代码大小的增加而增加。审核:Is it a good idea to typedef pointers?.
(注意:很好地使用解引用的指针来设置sizeof中的类型大小)
链接列表
链表只是一种巧妙的数据结构,它允许您遍历多个独立分配的节点。每个节点包含一些data,然后是指向列表中下一个节点的指针,如果该节点是列表中的最后一个节点,则为NULL。
(对于双向链表,您只需添加一个prev 指针,该指针也指向列表中当前节点之前的节点。您还有最后一个节点指向的 循环 列表回到第一个允许从列表中的任何节点迭代到任何其他节点的迭代,无论您从哪个节点开始迭代。对于双向循环列表,您可以从任何节点在两个方向上迭代整个列表)
在你的情况下,你的清单很简单:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| data | | | data | | | data |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
您的data 是一个整数值,而您的next 指针仅保存列表中下一个节点的地址,或者NULL 如果它是列表中的最后一个节点。添加您的数据,您的列表将是:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| 1 | | | 4 | | | 9 |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
创建列表时,第一个节点通常称为列表的head,最后一个节点称为列表的tail。您必须始终保留指向列表头部的指针,因为该指针包含起始列表地址。为了有效地插入列表,保留一个指向 tail 节点的指针也是一个好主意,这样您就可以简单地插入新节点,而无需每次遍历列表以找到最后一个节点,例如:
Node *newnode = malloc(sizeof(*newnode)); /* allocate */
newnode->next = NULL; /* initialize next NULL */
tail->next = newnode; /* assign to tail */
tail = newnode; /* set new tail at newnode */
列表是 C 语言的基础,在 Linux 内核本身中有很多使用。花时间理解它们以及如何用不同的变体编写它们。你会很高兴你做到了。最后,别忘了写一个简单的函数来在你完成后释放你的列表(如果分配了data,也释放它)。一个简单的 free_list 函数是:
void free_list (Node *list)
{
while (list) {
Node *victim = list; /* separate pointer to node to free */
list = list->next; /* can you see why you iterate next... */
free (victim); /* before you free the victim node? */
}
}
如果您还有其他问题,请告诉我。