【问题标题】:Explanation of code (linked list C)代码说明(链表C)
【发布时间】:2013-03-04 17:15:07
【问题描述】:

这不是我的代码。我从这个网站上取下了这段代码:

http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/linklist.html

我正在使用有关如何构建链接列表的参考资料。我对发生的事情有点困惑。有人可以向我解释发生了什么。我会用 1-5 标记让我感到困惑的地方。

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

struct list_el {
   int val;
   struct list_el * next;
};

typedef struct list_el item;

void main() {
   item * curr, * head;
   int i;

   head = NULL;   //1

   for(i=1;i<=10;i++) {
      curr = (item *)malloc(sizeof(item));
      curr->val = i;
      curr->next  = head; //2
      head = curr; //3
   }

   curr = head; // 4

   while(curr) {  //5
      printf("%d\n", curr->val);
      curr = curr->next ;
   }
  1. head = NULL → 为什么将 head 设置为 NULL?我知道你应该这样做(我这样做是出于习惯),但我真的不知道为什么。

  2. curr->next = head → 我也从来没有真正理解过这一点。也许我对“头”的定义是错误的,但是在常规链表中,它是列表中的起始节点还是最后一个节点?我一直认为它是起始节点,但在这一行中,它看起来像是最后一个节点。

  3. head = curr → 为什么我们将它设置为等于 curr?

  4. curr = head → 然后在循环完成后设置 curr = head。

  5. while(curr) → 只是为了确保这是遍历列表,它相当于 while(curr != NULL) 对吗?

【问题讨论】:

  • 通过在前端附加节点来构建列表,并调整head指向新节点。
  • 这段代码构建了一个链表,因此可能有助于清楚地了解链表是什么:en.wikipedia.org/wiki/Linked_list

标签: c linked-list head


【解决方案1】:

#1:head = NULL

初始化指针一般建议在 (1) 声明时或 (2) 在声明后立即将指针初始化为 NULL。如果程序员错误地取消引用未初始化的指针,则会返回垃圾值。通常,如果您的静态分析器和编译器不显示未初始化指针的警告或错误消息,这将非常难以调试。

有关更多信息,请参阅Steve McConnell's Code Complete: A Practical Handbook of Software ConstructionDefensive Programming 上的维基百科页面。

#2:curr-&gt;next = head

构建链表curr 节点正在“链接”到序列中先前创建的节点。

#3:head = curr

正在更新头指针。正在更新head 指针以指向最近的malloced 节点。

下图显示了步骤 #2 和 #3:

#4:curr = head

重新初始化指针。此步骤类似于步骤#2:curr-&gt;next = head。通过将curr 节点设置为headcurrwhile 循环中“准备好”进行链表遍历。打个比方,这就像在循环开始时将迭代变量初始化为 0(即i = 0)。为了可视化这一步,请参考下图显示此语句执行之前/之后:

#5:while(curr)

遍历列表。 鉴于curr 指向第一个节点(从步骤#4 开始),这个while 循环遍历列表直到curr-&gt;next 返回NULL。用一种不太抽象的形式,我们可以将这条语句重写为while(curr != NULL)

【讨论】:

  • 一个真正优秀的答案。非常解释和易于理解。与链表 atm 苦苦挣扎,这解决了它。谢谢。
【解决方案2】:
  1. head 指向列表的头部。由于列表当前为空,因此设置为 null
  2. 将节点添加到列表时,将“next”指针设置为列表的当前头。将新节点放在列表的头部。
  3. 您将“head”设置为“curr”以使新节点成为列表的头部。
  4. 循环结束后,您将重新使用“curr”变量来遍历列表。
  5. 您将依次遍历每个节点的列表设置“curr”,直到您离开列表底部(其中 curr->next 为空)

【讨论】:

    【解决方案3】:

    (1)。您需要将其设置为某种东西,并且使用 NULL 是一种表示它没有指向任何东西的方式。通常 NULL 与 0 相同。在某些语言中,您不需要初始化变量,因为它会自动将其设置为 nil。但是 C 不这样做,所以你必须自己做。

    (2)。 head 指向列表的第一个节点。起初,它是 NULL,这意味着列表是空的,因此 head 没有指向任何东西。 cur 是要插入列表的新节点。 curr-&gt;next 想要指向现有列表的第一个节点,因此将 curr-&gt;next 设置为 head

    (3)。此时head 不再指向第一个节点。第一次通过循环,它看起来像这样:

    curr-->node1-->NULL 头--^

    但总的来说它看起来像这样

    curr-->node3-->node2-->node1-->NULL 头--^

    所以我们需要更新head 指向第一个节点。由于curr指向的是新创建的节点,该节点位于最前面,我们只需将head设置为与curr指向同一个节点即可。

    (4)。程序的第一部分已经完成。 curr 不再需要,因为它用于跟踪我们创建的新节点。这是一个临时变量。这行curr = head 意味着我们要将curr 初始化到列表的开头。我们本可以使用另一个变量来使其更具可读性,但您通常会看到临时变量的重用。

    (5)。正确的。您可能会看到 NULL 定义为 (void*)0,因此它与 0 相同。除了 60 或 70 年代的真正旧机器之外,您可能永远不会看到除 0 之外的其他值。所以从逻辑上讲,它相当于: while (curr != 0)while (curr) 相同。

    【讨论】:

      【解决方案4】:

      1. head = NULL → 为什么 head 被设置为 NULL?
      初始化变量是个好习惯。在某些系统上,声明的变量在地址空间被抓取时会发生在内存中。

      2。 curr->next = head → 我也从来没有真正理解过这一点。也许我对“头”的定义是错误的,但是在常规链表中,它是列表中的起始节点还是最后一个节点?我一直认为它是起始节点,但在这一行中,它看起来像是最后一个节点。
      是的,头部是起始节点。

      3. head = curr → 为什么我们将它设置为等于 curr?
      这个循环在这里添加新节点作为头部。像栈一样。其他方法在尾部添加新节点。两种方式仍然是“链表”。

      4. curr = head → 然后在循环完成后设置 curr = head。
      curr 就像一个索引,一个工作变量,因此您不会破坏数据结构。他完成后正在重置它。如果愿意的话,“倒带”。

      5. while(curr) → 只是为了确保,这是遍历列表,它相当于 while(curr != NULL) 对吗?
      是的,这是您在 C 中发现的隐含内容之一。while 循环中的所有内容都隐含为 while(whatnot != 0) 和 null == 0。

      【讨论】:

      • 好吧,这就是我感到困惑的地方。en.wikipedia.org/wiki/Linked_list 在单链表部分中。带有“x”的框是头部还是尾部?
      • @juice:里面有“X”的框是空地址。最后一个元素指向它以显示“嘿,我是最后一个,我身后没有人”。遍历此列表的循环将在最后一项中看到此 NULL 指针,然后退出循环。
      • 是的,在那个例子中,#12 是头部的值,#37 是尾部的值。
      【解决方案5】:

      首先,您可以在Linked List Head Is Always NullSimple C++ Linked List 中找到为什么head 始终为NULL 的问题的答案。初学者的教程你可以找到singly linked list in c。语句 head=curr 通过分配内存将指针头的值 NULL 与接收非零值的当前指针的值相关联。 while(curr) 是一个循环,只要 curr 与 NULL 不同,NULL 就会运行,NULL 作为与指向地址相关联的零值的宏。

      【讨论】:

        【解决方案6】:

        我们从零开始。就是这样

        head = NULL;
        

        告诉我们。我们还没有列表,所以我们无法访问它。

        现在我们从 1 循环到 10。我们从后到前构建一个列表。 HEAD 为 NULL,因此“最后一个”(第一个创建的)指向 NULL:

        curr->next  = head; // head is NULL in the first loop
        

        HEAD 现在设置为这个新元素:

        head = curr;
        

        第二次通过这个循环,head 存储指向最后创建的项目的指针。然后新创建的将指向它。我们将此新项设置在最后一项之前。

        设置

        head = curr;
        

        需要完成,以确保在下一个循环中该 head 包含正确的指针。之所以称为 head,是因为它始终存储到那时已创建的列表的开头。

        //4 真的没有必要。

        之前的最后一次操作是:

        head = curr;
        

        所以

        curr = head;
        

        毫无意义。

        第五个遍历列表。 “curr”指向第一项(具有非 NULL 地址)并在每个循环中设置为 curr->next。一旦 curr 为 NULL(在最后一项),则该语句不再正确。

        【讨论】:

          【解决方案7】:

          在第4个问题中,我认为curr=head没有必要。因为当循环结束时,curr和head指针指向同一个节点(i=10的节点)。 但这是个好习惯。

          【讨论】:

            猜你喜欢
            • 2016-06-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-25
            • 2013-09-12
            • 2017-01-23
            • 2014-09-21
            • 2015-01-13
            相关资源
            最近更新 更多