【问题标题】:C - function that creates linked list only returns first nodeC - 创建链表的函数只返回第一个节点
【发布时间】:2018-05-07 08:38:32
【问题描述】:

我发现了其他类似但不完全相同的问题,如果我弄错了,请留下链接:)

我一直在尝试用 C 实现一个 shell,在解析管道时,我考虑过使用 char** args 的链表。

我的解析函数在返回整个列表时出现问题。我使用 tmp 节点在创建新节点时继续移动,但是当我想返回原始头时,它的下一个是 NULL,我认为指向我头的指针 tmp 应该只是一个指针,并且必须进行更改在我的头上。

这里是简化的代码,只有问题。

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
    int data;
    struct node* next;
} node ;
node* foo()
{
    node* head=malloc(sizeof(node));
    node* tmp=head;
    int i=0;
    for(i=0;i<5;i++)
    {
        tmp=tmp->next;
        tmp=malloc(sizeof(node));
        tmp->data=i;
    }
    return head;
}
int main()
{
    node* list=foo();
    while(list)
    {
        printf("this is your %d\n",list->data);
        list=list->next;
    }
}

如果你能指出我正确的方向或告诉我我做错了什么,那就太好了。

【问题讨论】:

  • 第一次来:tmp = tmp-&gt;nexttmp-&gt;next从未初始化过。
  • 我后来用tmp=malloc(sizeof(node))malloc'd
  • 这就是问题所在。您 之后 分配了它。您可能对编程的工作原理有一个严重的误解。
  • tmp=tmp-&gt;next; tmp=malloc(sizeof(node));没有意义,就像写a = 5; a = 10一样。

标签: c linked-list singly-linked-list


【解决方案1】:
node* head=malloc(sizeof(node));
node* tmp=head;
int i=0;
for(i=0;i<5;i++)
{
    tmp=tmp->next;
    tmp=malloc(sizeof(node));
    tmp->data=i;
}
return head;

这里你已经创建了 head 并给了空间,但你从未初始化它并在初始化它之前返回它

【讨论】:

    【解决方案2】:

    该函数没有意义,因为每个已分配节点的数据成员 next 未初始化。在循环中改变的是变量tmp

    函数可以如下所示

    node* foo()
    {
        const int N = 5;
        node *head = NULL;
    
        node **current = &head;
    
        for ( int i = 0; i < N; i++ )
        {
            *current = malloc(sizeof( node ) );
    
            if ( *current )
            {
                ( *current )->data = i;
                ( *current )->next = NULL;
                current = &( *current )->next;
            }
        }
    
        return head;
    }
    

    与其使用幻数5,不如指定应该在列表中创建多少个节点以及作为函数参数的初始值。

    例如

    node* foo( size_t n, int init_value )
    {
        node *head = NULL;
    
        node **current = &head;
    
        for ( size_t i = 0; i < n; i++ )
        {
            *current = malloc(sizeof( node ) );
    
            if ( *current )
            {
                ( *current )->data = init_value++;
                ( *current )->next = NULL;
                current = &( *current )->next;
            }
        }
    
        return head;
    }
    

    考虑到在 main 中,指针列表在循环中被覆盖。因此,您将无法再访问该列表,因为头节点的地址将丢失。使用中间变量。例如

    int main( void )
    {
        node *list = foo();
        for ( node *current = list; current != NULL; current = current->next )
        {
            printf("this is your %d\n", current->data);
        }
    }
    

    根据 C 标准,不带参数的函数 main 应声明为

    int main( void )
    

    【讨论】:

    • 我认为完全不需要你的双重间接。只需 malloc head 然后 tmp=head 然后返回 head 就可以了。
    • 是的,在我的实际程序中我这样做了,我只是简化以强调问题,而不是发布我的整个代码:P
    • @PaulOgilvie 该功能可以通过不同的方式实现。这并不意味着如果存在另一种方式来实现该功能,那么当前的方式是不正确的。:)
    • 对不起,弗拉德,我同意这一点;但是,对于已经在苦苦挣扎的当前用户,您的双重间接使事情变得过于复杂。首选 KISS。
    • @PaulOgilvie 你错了。我的实现很简单,没有部分案例。此外,正如我在第二个函数实现中展示的那样,它可以在不改变逻辑的情况下变得更通用。程序员的资格越少,他的代码包含的部分案例就越多。另一方面,程序员的资质越高,他编写的代码就越通用。
    【解决方案3】:

    你需要malloctmp->next 再分配给tmp,像这样:

    for(i=0;i<5;i++)
    {
        tmp->next = malloc(sizeof(node));
        tmp=tmp->next;
        tmp->data=i;
        tmp->next = NULL;
    }
    

    这个输出:

    this is your 0
    this is your 0
    this is your 1
    this is your 2
    this is your 3
    this is your 4
    

    【讨论】:

    • ...和tmp-&gt;next= 0; as malloc 不会初始化内存(因此您不会知道列表的结束位置)。
    • 所以我每次都需要将 tmp->next 设置为 NULL ?
    • 虽然比原来的程序好一点,但还是错了。
    • Reda,您当前正在分配长度为 5 的列表,因此您知道长度。我假设这是为了测试,所以在“现实生活”中,你添加一个节点、做某事、附加一个节点等。任何遍历列表的进程都想知道结尾在哪里,这就是 next 所在的位置零。因此,您在完成时将next 设置为零。无论是“每次”还是在某些时候都是我留给你的逻辑。
    • 我编辑了答案以添加@PaulOgilvie 提到的next 的初始化。
    猜你喜欢
    • 1970-01-01
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2020-11-20
    • 2011-11-05
    • 1970-01-01
    相关资源
    最近更新 更多