C中的循环链表没有给出所需的输出

C中的循环链表没有给出所需的输出,c,pointers,linked-list,C,Pointers,Linked List,我试图用C语言制作一个循环链表,但遇到了一些麻烦。我很确定这是指针问题,我正在学习C语言,指针是一个弱点。代码如下: #include <stdio.h> #include <stdlib.h> #include "cl.h" nodeptr add_to_end(nodeptr head, int val) { if (head == NULL) { nodeptr new_node = (nodeptr)malloc(sizeof(n

我试图用C语言制作一个循环链表,但遇到了一些麻烦。我很确定这是指针问题,我正在学习C语言,指针是一个弱点。代码如下:

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

nodeptr add_to_end(nodeptr head, int val)
{
    if (head == NULL)
    {
        nodeptr new_node = (nodeptr)malloc(sizeof(node));
        new_node->data = val;
        new_node->next = NULL;
        return new_node;
    } else {
        head->next = add_to_end(head->next,val);
        return head;
    }
}


void print_piles(nodeptr nodeHead)
{
    if (nodeHead == NULL)
        return;
    printf("%d\n ",nodeHead->data);
    print_piles(nodeHead->next);
}



int main(int argc, char *argv[])
{
    nodeptr head = NULL;
    nodeptr tail = NULL;
    int i = 0;

    head = add_to_end(head,i);
    i++;
    tail = add_to_end(tail,i);
    head->next = tail;
    i++;
    tail = add_to_end(tail,i);
    tail->next = head;

    printf("%d\n ",head->data);
    printf("%d\n ",tail->data);
    tail = tail->next;
    printf("%d\n ",tail->data);
    return 0;
}
输出为:

0
1
0
我希望得到的是:

0
1
2
我需要更改什么?

您需要添加 tail=tail->这两行之间的下一行:

tail = add_to_end(tail,i);
tail->next = head;
然后使用tail->next获取新节点

因此,将主代码更新为-

int main(int argc, char *argv[])
{
    nodeptr head = NULL;
    nodeptr tail = NULL;
    int i = 0;

    head = add_to_end(head,i);
    i++;
    tail = add_to_end(tail,i);
    head->next = tail;
    i++;

    // Add new node to current tail's next
    tail->next = add_to_end(tail,i);
    // Change tail to point to latest added node
    tail = tail->next
    tail->next = head;

    printf("%d\n ",head->data);
    printf("%d\n ",tail->data);
    tail = tail->next;
    printf("%d\n ",tail->data);
    return 0;
}
您需要添加 tail=tail->这两行之间的下一行:

tail = add_to_end(tail,i);
tail->next = head;
然后使用tail->next获取新节点

因此,将主代码更新为-

int main(int argc, char *argv[])
{
    nodeptr head = NULL;
    nodeptr tail = NULL;
    int i = 0;

    head = add_to_end(head,i);
    i++;
    tail = add_to_end(tail,i);
    head->next = tail;
    i++;

    // Add new node to current tail's next
    tail->next = add_to_end(tail,i);
    // Change tail to point to latest added node
    tail = tail->next
    tail->next = head;

    printf("%d\n ",head->data);
    printf("%d\n ",tail->data);
    tail = tail->next;
    printf("%d\n ",tail->data);
    return 0;
}

不是指针问题!你正在得到明确的行为。但是你循环链接的步骤是错误的。下面我解释了主功能中的步骤:

步骤1:

因此创建了一个头部节点,假设节点地址为201:

head: 201
[ 0, NULL]
步骤2:

因此创建了一个尾部节点,假设节点地址为304:

tail: 304
[ 1, NULL]
步骤3: 分配后:head->next=tail;:链表类似于:

head: 201     tail: 304 
[ 0, 304] --► [1, NULL]
步骤4: 在以下两个代码序列之后:

i++;
tail = add_to_end(tail,i);
您已经创建了一个新节点,并附加了值为2的节点。假设链接列表中的地址为349,列表如下所示:

head: 201     tail: 304         : 349
[ 0, 304] --► [ 1, 349] --► [ 2, NULL]
步骤5: 现在的错误:根据您的添加函数,尾值仍然是304,所以在上次分配尾->下一步=头之后;您得到的结果如下所示:

head: 201     tail: 304         : 349
[ 0, 304] --► [ 1, 349]    [ 2, NULL]
   ▲             |
   +-------------+  
所以尾巴的下一个是头部,这就是为什么你们的输出是0,1,0

请注意,您还有内存泄漏

为什么会这样?add函数最后附加一个节点,并返回传递给您正在传递的函数的head,tail我正在评论

nodeptr add_to_end(nodeptr head, int val)
{                     //    ^ is tail at third call
    if (head == NULL)// if first node is NULL
    {
        nodeptr new_node = (nodeptr)malloc(sizeof(node));
        new_node->data = val;
        new_node->next = NULL;
        return new_node; <-- "return only if new node is first node"
    } else {
        head->next = add_to_end(head->next,val);
        return head; <--- "Return `head` that is passed to function at calling"
    }
}
所以当你调用tail=add_to_endtail时,i;若tail不为NULL,则函数add_to_end返回我的示例地址为304中较旧的tail


您应该纠正tail->next=head;as tail->next->next=头部;你会得到预期的结果

不是指针问题!你正在得到明确的行为。但是你循环链接的步骤是错误的。下面我解释了主功能中的步骤:

步骤1:

因此创建了一个头部节点,假设节点地址为201:

head: 201
[ 0, NULL]
步骤2:

因此创建了一个尾部节点,假设节点地址为304:

tail: 304
[ 1, NULL]
步骤3: 分配后:head->next=tail;:链表类似于:

head: 201     tail: 304 
[ 0, 304] --► [1, NULL]
步骤4: 在以下两个代码序列之后:

i++;
tail = add_to_end(tail,i);
您已经创建了一个新节点,并附加了值为2的节点。假设链接列表中的地址为349,列表如下所示:

head: 201     tail: 304         : 349
[ 0, 304] --► [ 1, 349] --► [ 2, NULL]
步骤5: 现在的错误:根据您的添加函数,尾值仍然是304,所以在上次分配尾->下一步=头之后;您得到的结果如下所示:

head: 201     tail: 304         : 349
[ 0, 304] --► [ 1, 349]    [ 2, NULL]
   ▲             |
   +-------------+  
所以尾巴的下一个是头部,这就是为什么你们的输出是0,1,0

请注意,您还有内存泄漏

为什么会这样?add函数最后附加一个节点,并返回传递给您正在传递的函数的head,tail我正在评论

nodeptr add_to_end(nodeptr head, int val)
{                     //    ^ is tail at third call
    if (head == NULL)// if first node is NULL
    {
        nodeptr new_node = (nodeptr)malloc(sizeof(node));
        new_node->data = val;
        new_node->next = NULL;
        return new_node; <-- "return only if new node is first node"
    } else {
        head->next = add_to_end(head->next,val);
        return head; <--- "Return `head` that is passed to function at calling"
    }
}
所以当你调用tail=add_to_endtail时,i;若tail不为NULL,则函数add_to_end返回我的示例地址为304中较旧的tail


您应该纠正tail->next=head;as tail->next->next=头部;你会得到预期的结果

如果你想学习C语言,通过实现一个循环链表,你应该试着正确地实现它,而不是强迫一个非循环链表进入一个循环链表,通过执行tail->next=header,因为如果你尝试在之后向链表中添加一个项,你会得到无限递归挂起,有点像无限循环,因为您的算法检查NULL作为终止条件


循环列表有一个指向头和尾的指针,当你到达最后一个节点时,通过比较当前节点和尾来结束。

如果你想学习C,通过实现循环链表,你应该尝试正确地实现它,而不是强迫非循环列表进入循环列表,通过执行tail->next=header,因为如果您尝试在之后向列表中添加一个项,您将得到无限递归挂起,有点像无限循环,因为您的算法将检查NULL作为终止条件

int main(int argc, char *argv[])
{
    nodeptr head = NULL;
    nodeptr tail = NULL;
      nodeptr tail1 = NULL;

    int i = 0;

    head = add_to_end(head,i);
    i++;
    tail = add_to_end(tail,i);
    head->next = tail;
    i++;
    tail1 = add_to_end(tail1,i);
    tail->next = tail1;
    tail1->next= head;

    printf("%d\n ",head->data);
    printf("%d\n ",tail->data);
    tail = tail->next;
    printf("%d\n ",tail->data); 

    return 0;
}

一个循环列表,有一个指向头部和尾部的指针,在到达最后一个节点时,通过比较当前节点和尾部来结束。

我建议您在调试程序中一行一行地逐步完成代码,同时将列表写在纸上。事实上,我更愿意建议你先把它放在纸上,然后创建代码来匹配它。哦,当我说先放在纸上,我的意思是一步一步。与添加第一个节点类似,在头部和尾部添加第二个节点,在头部和尾部添加第三个和第四个节点。如果你能做到这一点,那么就很容易翻译成代码。我建议你在调试程序中一行一行地完成代码,同时在纸上写下你的列表。事实上,我更愿意建议你先把它放在纸上,然后创建代码来匹配它。哦,当我说先放在纸上,我的意思是一步一步来-
int main(int argc, char *argv[])
{
    nodeptr head = NULL;
    nodeptr tail = NULL;
      nodeptr tail1 = NULL;

    int i = 0;

    head = add_to_end(head,i);
    i++;
    tail = add_to_end(tail,i);
    head->next = tail;
    i++;
    tail1 = add_to_end(tail1,i);
    tail->next = tail1;
    tail1->next= head;

    printf("%d\n ",head->data);
    printf("%d\n ",tail->data);
    tail = tail->next;
    printf("%d\n ",tail->data); 

    return 0;
}

步与添加第一个节点类似,在头部和尾部添加第二个节点,在头部和尾部添加第三个和第四个节点。如果你能做到这一点,那么就很容易翻译成代码。哇,这真是一个很好的解释。非常感谢你!哇,这真是一个很好的解释。非常感谢你!