我正在创建一个简单的整数链接列表,然后将其反转。在反转时,原始列表中的最后一个整数不会被打印。而是打印垃圾值。这是代码:
#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("%d\t",(*pre)->node);
}
*temp = *pre;
}
}
void print(struct list *head)
{
if(head==NULL)
return;
else
{
while(head!=NULL)
{
printf("%d\t",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 hello 6532425 60 50 40 30 20 10
为什么?
答案 0 :(得分:2)
问题出在这个声明中:
struct list **pre, **aft, **head;
因此,它们指向指向列表的指针,然后,您执行以下操作:
*pre = NULL;
问题是pre
尚未初始化,因此此时它会保留垃圾。您基本上将内存中的随机地址设置为NULL。
您有两种选择:为它们分配空间(使用malloc和之后的空闲),或者将它们更改为:
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("%d\t",pre->node);
}
*temp = pre;
}
}
这样做,我得到以下输出:
10 20 30 40 50 60 70 hello 70 60
50 40 30 20 10
编辑:
我还注意到您正在更改head
和insert
内的print
值。我建议使用时态变量来迭代列表。这也让您摆脱了main
与tmp
使用的技巧。
无论如何,可以看到修改后的完整代码here。如果您仍然遇到麻烦,请使用仍然失败的修改后的代码发布更新或Ideone链接。
答案 1 :(得分:2)
首先,通过这样做来解除引用并写入不确定的位置:
struct list **pre, **aft, **head;
*pre = NULL; // <=== HERE
*head = *temp; // <=== HERE
这些指针都没有被初始化为任何东西,因此是不确定的。取消引用它们进行读取,写入甚至评估指针值本身是未定义的行为。
修复这很容易,因为这个函数不需要任何指针到指针变量,除了传入的头指针(它必须有by-address才能重置新的列表头一次)它是颠倒的)。
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;
此代码盲目地覆盖传入的头指针by-address,并且在此过程中泄漏任何先前分配的节点,除了最后添加的节点。如果您要接收双指针并使用它来遍历列表以查找新插入的位置,请正确执行。在tmp
中使用main()
播放的指针游戏不一定是必要的,并且通过以下实现,它不是:
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循环的break条件:
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