我正在创建一个简单的整数链接列表,然后反转它。反转时,不会打印原始列表中的最后一个整数。而是打印垃圾值。这是代码:
#include<stdio.h>
#include<stdlib.h>
struct list
{
int node;
struct list *next;
};
void insert(struct list **, int);
void print(struct list *);
int main()
{
struct list *mylist= NULL, *tmp = NULL;
insert(&mylist, 10);
tmp = mylist;
insert(&mylist, 20);
insert(&mylist, 30);
insert(&mylist, 40);
insert(&mylist, 50);
insert(&mylist, 60);
insert(&mylist, 70);
mylist=tmp;
reverse(&mylist);
printf("hello ");
print(mylist);
return 0;
}
void reverse(struct list **temp)
{
struct list **pre, **aft, **head;
*pre = NULL;
*head = *temp;
if(*head == NULL )
{
return;
}
else
{
while((*head)!= NULL)
{
*aft =(*head)->next;
(*head)->next = *pre;
*pre = *head;
*head = (*aft);
printf("%dt",(*pre)->node);
}
*temp = *pre;
}
}
void print(struct list *head)
{
if(head==NULL)
return;
else
{
while(head!=NULL)
{
printf("%dt",head->node);
head=head->next;
}
}
}
void insert(struct list **head, int value)
{
struct list *new_node;
new_node = (struct list *)malloc(sizeof(struct list));
//node Creation
new_node->node=value;
new_node->next=NULL;
//Adding Node to list
if(*head==NULL)
{
*head=new_node;
}
else
{
while((*head)->next!=NULL)
{
*head=(*head)->next;
}
(*head)->next=new_node;
}
}
输出:10 20 30 40 50 60 6532425你好6532425 60 50 40 30 20 10
为什么?
首先,通过执行以下操作取消引用和写入不确定的位置:
struct list **pre, **aft, **head;
*pre = NULL; // <=== HERE
*head = *temp; // <=== HERE
这些指针都不会初始化为任何内容,因此是不确定的。 取消引用它们以读取、写入甚至计算指针值本身是未定义的行为。
修复这个问题很容易,因为这个函数不需要任何指针到指针变量,除了传入的头部指针(一旦它被反转,它必须具有按地址重置新的列表头)。
void reverse(struct list **head)
{
struct list *back = NULL, *cur = *head, *fwd = NULL;
while (cur && cur->next)
{
fwd = cur->next;
cur->next = back;
back = cur;
cur = fwd;
}
if (cur)
cur->next = back;
*head = cur;
}
也就是说,有证据表明,你使用指针到指针的工作需要更多的练习。还有其他错误,如下所述
insert()
内存泄漏
在insert()
函数中:
while((*head)->next!=NULL)
{
*head=(*head)->next;
}
(*head)->next=new_node;
此代码按地址盲目覆盖传入的头指针,并在此过程中泄漏除最后一个添加的节点之外的任何先前分配的节点。如果您要接收双指针并使用它来浏览列表以查找新插入的位置,请正确执行此操作。在main()
中使用tmp
玩的指针游戏应该是不必要的,并且通过以下实现,它不是:
void insert(struct list **head, int value)
{
// find the address of the last `next` pointer in
// the list. note: it may be the head pointer itself
while (*head)
head = &(*head)->next;
*head = malloc(sizeof(**head));
(*head)->node = value;
(*head)->next = NULL;
}
简化print()
您的print()
代码中也存在轻微的不便。无需对传入的指针进行初始检查,即为 NULL。只需使用 while 循环的中断条件:
void print(struct list *head)
{
while(head)
{
printf("%d ",head->node);
head=head->next;
}
printf("n");
}
将一切整合在一起
使用上述实现和以下main()
:
int main()
{
struct list *mylist = NULL;
insert(&mylist, 10);
insert(&mylist, 20);
insert(&mylist, 30);
insert(&mylist, 40);
insert(&mylist, 50);
insert(&mylist, 60);
insert(&mylist, 70);
print(mylist);
reverse(&mylist);
print(mylist);
return 0;
}
输出
10 20 30 40 50 60 70
70 60 50 40 30 20 10
问题出在这个声明中:
struct list **pre, **aft, **head;
因此,它们是指向列表指针的指针,然后,您执行以下操作:
*pre = NULL;
问题是pre
尚未初始化,因此此时它包含垃圾。您基本上将内存中的随机地址设置为 NULL。您有两种选择:为它们分配空间(使用 malloc 并在之后使用 free),或者将它们更改为这样:
struct list *pre, *aft, *head;
这样,就可以安全地分配它们。您的函数将像这样修改:
void reverse(struct list **temp) {
struct list *pre, *aft, *head;
pre = NULL;
head = *temp;
if(head == NULL ) {
return;
} else {
while(head!= NULL) {
aft =head->next;
head->next = pre;
pre = head;
head = aft;
printf("%dt",pre->node);
}
*temp = pre;
}
}
这样做,我得到以下输出:
10 20 30 40 50 60 70 hello 70 60
50 40 30 20 10
编辑:
我还注意到您正在更改函数 insert
和 print
中的 head
值。我建议改用时态变量来迭代列表。这也使您摆脱了在main
中使用的技巧 tmp
.
无论如何,修改的完整代码可以在这里看到。如果您仍然给您带来麻烦,请发布更新或 Ideone 链接,其中包含仍然失败的修改代码。