【问题标题】:Printing linked List infinite loop C打印链表无限循环C
【发布时间】:2016-12-01 21:56:48
【问题描述】:

添加节点后,我正在尝试打印链接列表。我有一个虚拟节点来启动列表

   Node **nodeArray;
    nodeArray = malloc(10 * sizeof(Node *));

    int i;
    for (i = 0; i < 10; i++) {
        nodeArray[i] = malloc(sizeof(Node));    
    }

    if (userChoice == 'a') 
        add(&nodeArray, setNumber);

void add(Node ***nodeArray, int setNumber) {
        char userString[5];
        printf("Please enter some data: ");
        scanf("%s", userString);

        Node *head = *nodeArray[setNumber];     /* head pointer to first element of array (dummy) */
        Node *newNode = malloc(sizeof(Node));   /* new node to be added to array */

        strncpy(newNode->data, userString, sizeof(newNode->data));  /* copies string entered by the user to data field of new node */
        newNode->next = NULL;   /* initializes next field of new node to NULL */

        Node *tmp = head;   /* pointer to head of list */

        while (!tmp->next) {
            tmp->next = newNode;    /* inserts new node into array */
            tmp = newNode;      /* points head to newly added node */
        }

        tmp = head;     /* points tmp back to head of list */

        printf("List is: ");
        while (tmp->next) {
            printf("%s", (tmp->data));
            tmp = tmp->next;
        }
}

但是当我打印时,我得到一个无限循环打印出新添加节点的数据字段。链接列表很糟糕......我做错了什么?

【问题讨论】:

  • 请提供minimal reproducible example。不需要像讲故事一样讲。只需展示 MCVE,因为我们可以自己阅读这些简单的代码,无需逐块解释。并且全部在一个块中,因此任何人都可以更轻松地复制以在需要时尝试。
  • 什么是nodeArray?你是说Node *head = *Node[setNumber]; 吗?
  • 查看编辑了解详情。

标签: c linked-list


【解决方案1】:
while (tmp->next) {
   tmp->next = newNode;    /* inserts new node into array */
   tmp = newNode;      /* points head to newly added node */
}

在这个 sn-p 中,您将失去对下一个节点的引用,而只是将 newNode 添加到头部旁边。例如,您有以下列表:

[1]->[2]->[3]

并且您想将一个新元素推送到该列表中:[4],当您执行推送功能(上面的 sn-p)时会发生什么:

tmp = head; // tmp = [1]
while(tmp->next) {
    tmp->next = newNode; // [1]->next = [4]
    tmp = newNode; // tmp = [4]
}

所以下一次 '(tmp->next)' 被评估时,它将被评估为:[4]->next,它将为 NULL,从而中断循环。您的列表将是:

[1]->[4]

其他元素丢失,因为您不再有指向它们的引用,这称为内存泄漏,因为您以后无法释放它们。

您可以编写推送以这种方式运行:

tmp = head;
while(tmp->next)
    tmp = tmp->next;
tmp->next = newNode // Adds new node to the tail of the linked list

【讨论】:

  • 抱歉,您能详细解释一下吗?
  • @namarino 当然。这就是你的 sn-p 中发生的事情:例如,你有这个列表 [1]->[2]->[3],你要添加 [4]。所以你设置 tmp = [1]。在第一次执行循环时,您设置 tmp->next = newNode,即 [1]->next = [4],然后设置 tmp = newNode,即。例如,tmp = [4]。因此,下一次循环时,它将评估 [4]->next 而不是 [2]->next 正如您所期望的那样。推送后的最终列表将是[1]->[4],[2]->[3]永远丢失。
  • 这很有意义。像我在上面所说的那样创建指向我的头指针的指针是否是个好主意 Node *head = *nodeArray[setNumber];然后节点 *tmp = head;还是我应该直接与 head 合作?
  • 只要你可以使用变量名来明确你的代码的“内部”工作,你就应该这样做。在这种情况下,您稍后将使用 tmp 并将其初始化为“head”,恕我直言,以这种方式使用它是个好主意。
【解决方案2】:

这是因为在此之后:

while (!tmp->next) {
    tmp->next = newNode;    /* inserts new node into array */
    tmp = newNode;      /* points head to newly added node */
}

head 指向 newNode,newNode->next 指向 newNode。

这就是问题所在。 实际上插入 newNode 是一个问题。你将不得不改变它。

【讨论】:

  • newNode->next 什么时候指向 newNode?它不是这样初始化的,而且这个循环似乎只改变了 head 指向的东西。
【解决方案3】:

我假设您正在尝试将新节点添加到数组的末尾(也称为推送)。 所以试试这个:

Node tmp=head; /* pointer to the head of list */
while (tmp->next) tmp=tmp->next; /* step from Node to Node till the last one */
tmp->next=newNode; /* tell that last one to point to the new Node you created */

【讨论】:

    【解决方案4】:

    您通过以下几行制作了一个封闭的圆圈链接列表:

    while (!tmp->next) {
        tmp->next = newNode;    /* inserts new node into array */
        tmp = newNode;          /* points head to newly added node */
    }
    

    所以在这之后实际上你会得到newNode-&gt;next = newNode,即`tmp->next = tmp。

    所以你应该这样做:

    while (tmp->next) {
        tmp = tmp->next;    //Find the last node
    }
    tmp->next = newNode;    //Inserts new node into the end of the array
    

    【讨论】:

    • tmp 是指向头的指针。节点 *head = *nodeArray[setNumber];然后是节点 *tmp = head;
    猜你喜欢
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多