C 理解链表的定义有困难

C 理解链表的定义有困难,c,pointers,struct,linked-list,C,Pointers,Struct,Linked List,我有一些关于链表定义的问题,因为它是在我的课堂上定义的 这就是所使用的: typedef struct node_t { int x; struct node_t *next; } *Node; 现在,我了解到,通过这种方式,我们创建了一种使用指向结构节点的指针的较短方法。节点将用作结构节点 现在,假设我们想要创建一个链表。例如: Node node1 = malloc(sizeof(*node1)); Node node2 = malloc(sizeof(*node2)); Node nod

我有一些关于链表定义的问题,因为它是在我的课堂上定义的

这就是所使用的:

typedef struct node_t {
int x;
struct node_t *next;
} *Node;
现在,我了解到,通过这种方式,我们创建了一种使用指向结构节点的指针的较短方法。节点将用作结构节点

现在,假设我们想要创建一个链表。例如:

Node node1 = malloc(sizeof(*node1));
Node node2 = malloc(sizeof(*node2));
Node node3 = malloc(sizeof(*node3));
node1->x = 1;
node1->next = node2;
node2->x = 4;
node2->next = node3;
node3->x = 9;
node3->next = NULL;
这大概就是我想象的,圆圈代表结构:

现在我知道这是错的,但我不明白为什么。我们有一个指针node1,它指向我们的结构。然后,我们指向节点2,它指向另一个结构,依此类推

另一件事是,我不明白怎么可能有更长的箭头在图片中。难道我们不应该只从圆圈的每个下部指向一个结构,而不是指向一个结构的指针吗?这怎么可能


如果在座的任何人能把事情说得更清楚一点,我们将不胜感激。非常感谢。

您有三个链接节点,以及指向它们的其他本地指针。 然而,节点并不知道关于这些本地指针的任何信息,即使使用它们的名称来引用节点通常很方便。 相反,它们知道序列中的下一个节点,分别是最后一个节点不知道

换句话说,你的形象是完全错误的

          +---+------+
node1 --> | 1 | next |
          +---+-|----+
                |
                v
          +---+------+
node2 --> | 4 | next |
          +---+-|----+
                |
                v
          +---+------+
node3 --> | 9 | NULL |
          +---+------+

赋值是一种传递操作。所以

node1->next = node2;
这意味着node1->next指向node2指向的任何节点。尤其是,node1->next并不指向node2本身

node1、node2和node3中的每一个都命名一个作为指针的变量

为什么??有人在typedef声明下面查看代码100行时,不会从本质上知道节点是类型还是指向类型的指针。这种类型的混淆只会随着代码大小的增加而增加。评论:

注意:使用取消引用的指针设置sizeof中的字体大小做得很好

链表

链表只是一种聪明的数据结构,它允许您在许多独立分配的节点上进行迭代。每个节点都包含一些数据,然后是指向列表中下一个节点的指针,如果该节点是列表中的最后一个节点,则为NULL

对于双链接列表,只需添加一个prev指针,该指针也指向列表中当前节点之前的节点。您还可以使用循环列表,其中最后一个节点指向第一个节点,从而允许从列表中的任何节点到任何其他节点进行迭代,而不管您使用哪个节点开始迭代。对于双链接循环列表,可以从任何节点在两个方向上迭代整个列表

在您的情况下,您的列表只是:

     node1    +-> node2    +-> node3
    +------+  |  +------+  |  +------+
    | data |  |  | data |  |  | data |
    |------|  |  |------|  |  |------|
    | next |--+  | next |--+  | next |---> NULL
    +------+     +------+     +------+
其中,数据是单个整数值,下一个指针仅保存列表中下一个节点的地址,如果是列表中的最后一个节点,则为NULL。添加数据后,您的列表将是:

     node1    +-> node2    +-> node3
    +------+  |  +------+  |  +------+
    |   1  |  |  |   4  |  |  |   9  |
    |------|  |  |------|  |  |------|
    | next |--+  | next |--+  | next |---> NULL
    +------+     +------+     +------+
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?    */
    }
}
创建列表时,第一个节点通常称为列表的头部,最后一个节点称为列表的尾部。您必须始终保留指向列表头的指针,因为该指针包含列表的起始地址。为了有效地插入到列表中,最好保留一个指向尾部节点的指针,这样您就可以简单地插入新节点,而无需每次迭代列表以查找最后一个节点,例如:

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内核本身使用了很多列表。花点时间理解它们,以及如何在不同的变体中编写它们。你会很高兴你这么做的。最后,不要忘记编写一个简单的函数,在完成时释放列表,如果分配了数据,也释放数据。一个简单的自由列表函数是:

     node1    +-> node2    +-> node3
    +------+  |  +------+  |  +------+
    |   1  |  |  |   4  |  |  |   9  |
    |------|  |  |------|  |  |------|
    | next |--+  | next |--+  | next |---> NULL
    +------+     +------+     +------+
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?    */
    }
}

如果您还有其他问题,请告诉我。

将节点定义为指针类型确实会导致混淆。在C语言中,约定是定义普通类型,并使指针明显可见,可以是Node*指针,也可以是类似Node_ptr的速记。这是因为。这区分了node1变量(恰好是指针)和它所指向的数据。非常感谢,我有两个问题。首先,我不明白为什么next不指向next指针。如果它像node1->next=*node2;我会理解,但事实并非如此。其次,如果是这样的话,为什么我们首先需要指向每个结构的指针?node1->next=node2将存储在node2标识的对象中的值复制到node1->next标识的对象中。这类似于int x=1,y;y=x;不会使y成为x的别名-它们仍然是不同的变量,但它们包含相同的值。在指针的情况下,您将得到两个指针对象,它们的值都指向同一个对象,而不是一个指向另一个对象,或者以某种方式等同于另一个对象。我想我明白了,感谢您的帮助。我不明白为什么使用node1->next=node2是正确的;而不是node1->next=*node2*节点
2对指针应用取消引用运算符。它是如何获得对象的值而不是它的地址(指针将包含地址)。或者从另一个角度看,node1->next的类型是struct node\u t*。这与node2的类型相同,但与*node2的类型不同。
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?    */
    }
}