我正在尝试在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;
}
答案 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->next
和p->prev
现在在循环内初始化为NULL
,循环后无需执行此操作。