双链表无法正确创建

时间:2014-03-16 15:54:33

标签: c list pointers

我正在尝试在C中创建一个双向链表,但它不起作用,我不知道为什么。它只打印我引入的最后一个元素。我没有看到创建列表的代码部分有任何问题。也许你能看到它?

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

typedef struct node
{
    int data;
    struct node *next;
    struct node *prev;
}NodeT;

struct d_linked_list
{
   NodeT *first;
   NodeT *last;
};

int main()
{
    int d;
    struct d_linked_list *l;
    NodeT *p,*q;
    p=(NodeT*)malloc(sizeof(NodeT));
    q=(NodeT*)malloc(sizeof(NodeT));
    l->first=NULL;
    l->last=NULL;
    while (fscanf(stdin,"%d",&d)!=EOF)
    {
        p->data=d;
        if (l->first==NULL)
        {
            l->first=p;
            l->last=p;
            p->next=NULL;
            p->prev=NULL;
        }
        else
        {
            l->last->next=p;
            p->prev=l->last;
            l->last=p;
        }
    }
    l->last->next=NULL;
    for (q=l->first;q!=NULL;q=q->next)
        printf("%d ",q->data);
    return 0;
}

3 个答案:

答案 0 :(得分:2)

经常出现一些问题,其中一些问题已在其他答案或评论中找到,有些问题(我认为)之前没有确定:

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

typedef struct node
{
    int data;
    struct node *next;
    struct node *prev;
}NodeT;

struct d_linked_list
{
   NodeT *first;
   NodeT *last;
};

到目前为止,非常好。

int main()
{
    int d;
    struct d_linked_list *l;

您没有为l分配空间。因此可能更简单(因此可能更好):

struct d_linked_list head;  // Or maybe list instead of head

然后在您的代码中引用head而不是l;您也可以使用l = &head;而无需进一步更改。

    NodeT *p,*q;
    p=(NodeT*)malloc(sizeof(NodeT));
    q=(NodeT*)malloc(sizeof(NodeT));

您永远不会使用为q分配的空间,并最终覆盖它,从而泄露。如果失败,你应检查malloc()是否有效,做了一些适当的事情(停止并收到错误信息?)。

    l->first=NULL;
    l->last=NULL;
    while (fscanf(stdin,"%d",&d)!=EOF)

你应该检查你有一个while (fscanf(stdin, "%d", &d) == 1)的整数;循环在EOF或转换失败时中断。

    {
        p->data=d;

您在循环之前分配了p,但每个后续条目都覆盖了相同的空间。您需要为读取的每个值分配一个新节点。 (这在以前没有被确定为问题 - 虽然我看到Filipe Gonçalves在我打字时将answer添加到他的{{3}}。)

        if (l->first==NULL)
        {
            l->first=p;
            l->last=p;
            p->next=NULL;
            p->prev=NULL;
        }
        else
        {
            l->last->next=p;
            p->prev=l->last;
            l->last=p;
        }
    }

表面上看,上面的代码看起来不错;我没有运行它,所以可能会出现我没有发现的问题。

我注意到没有彻底检查过&#39;菲利普指出,确实存在问题。我认为if子句是正常的,但else子句需要设置p->next = NULL;。通常,最好完全创建节点:p->data = d; p->next = NULL; p->prev = NULL:然后将节点挂钩到列表中。

    l->last->next=NULL;

这条线应该是不必要的。在循环的每个循环结束时,应该正确地形成列表。测试此方法的一种方法是在每个循环中打印出列表的内容(使用函数)。您还可以使用该函数代替后面的循环。我经常使用的界面设计是:

void dump_list(FILE *fp, char const *tag, struct d_linked_list const *list)

在给定的文件流上打印标识标记和列表的内容。我为每个重要的数据结构保留了这些函数,以便稍后调试更容易。

    for (q=l->first;q!=NULL;q=q->next)

此循环丢失了分配给q的空间。

        printf("%d ",q->data);

您应该在某个时候输出换行符。

您还应该通过释放所有分配空间的动作,只是为了确保您知道如何做到这一点。当您即将退出程序时,它并不重要,但如果您在长时间运行的程序中使用该列表,该程序每分钟需要一次列表,那么就会关闭并执行不相关的操作,然后你正在泄漏所有内存,你的长期运行的程序会在一段时间后停止运行,因为它缺少必要的内存(因为它已经泄漏 - 浪费了 - 列表中的内存)。

    return 0;
}

答案 1 :(得分:1)

尝试将p=(NodeT*)malloc(sizeof(NodeT));移动到循环的顶部。此外,您不需要malloc q中的值{。}}。

答案 2 :(得分:1)

您永远不会为l分配空间。因此,这些行取消引用无效指针:

l->first=NULL;
l->last=NULL;

在使用之前,您必须为l分配空间:

l = malloc(sizeof(*l));
l->first=NULL;
l->last=NULL;

此外,您需要为您阅读的每个新值分配一个新元素。因此,我会将p的分配移到循环中:

q=(NodeT*)malloc(sizeof(NodeT));
l->first=NULL;
l->last=NULL;
while (fscanf(stdin,"%d",&d)!=EOF)
{
    p=(NodeT*)malloc(sizeof(NodeT));
    /* ... */
}

并且您不需要为q分配空间(您仅将其用于遍历列表)。最后,正如评论中指出的那样,您应该检查fscanf()是否返回1,因为只有在这种情况下您才能确定d包含有效值。

把这一切放在一起:

int main()
{
    int d;
    struct d_linked_list *l;
    NodeT *p,*q;
    if ((l = malloc(sizeof(*l))) == NULL) {
        /* Handle malloc error */
    }
    l->first=NULL;
    l->last=NULL;
    while (fscanf(stdin,"%d",&d) == 1)
    {
        if ((p = malloc(sizeof(*p))) == NULL) {
            /* Handle malloc error... */
        }
        p->data=d;
        p->next = p->prev = NULL;
        if (l->first==NULL)
        {
            l->first=p;
            l->last=p;
        }
        else
        {
            l->last->next=p;
            p->prev=l->last;
            l->last=p;
        }
    }
    for (q=l->first;q!=NULL;q=q->next)
        printf("%d ",q->data);
    return 0;
}

更新:我更改了代码以检查malloc()的返回值,并取消了l->last->next = NULL; - p->nextp->prev现在在循环内初始化为NULL,循环后无需执行此操作。