C 删除链表元素会导致无限循环
我正在编写一个程序,该程序在输入中获取整数列表,并根据该整数执行以下操作:C 删除链表元素会导致无限循环,c,loops,linked-list,infinite,C,Loops,Linked List,Infinite,我正在编写一个程序,该程序在输入中获取整数列表,并根据该整数执行以下操作: 如果输入中的值为负值,则删除绝对值 如果数字是正数和偶数,则在列表顶部添加 如果数字是正数和奇数,则将其添加到列表的末尾 如果数字等于零,则结束程序并打印列表 我的问题是pop_el函数,它会导致列表上出现无限循环,因此当我打印列表时,程序会进入无限循环。 这是我的代码: #include <stdio.h> #include <stdlib.h> typedef struct ll_node_
#include <stdio.h>
#include <stdlib.h>
typedef struct ll_node_S * ll_node_ptr;
struct ll_node_S
{
int v;
ll_node_ptr next;
};
typedef struct ll_node_S ll_node;
ll_node_ptr push_tail(ll_node_ptr head, int v)
{
ll_node_ptr backup = head;
ll_node_ptr current = head;
while(current->next != NULL)
{
current = current->next;
}
current->next = (ll_node_ptr) malloc(sizeof(ll_node));
current->v = v;
return backup;
}
ll_node_ptr push_head(ll_node_ptr head, int v)
{
ll_node_ptr new_head = (ll_node_ptr)malloc(sizeof(ll_node));
new_head->v = v;
new_head->next = head;
return new_head;
}
ll_node_ptr pop_el(ll_node_ptr head, int el)
{
ll_node_ptr backup = head;
ll_node_ptr current = head;
ll_node_ptr previous = NULL;
int found = 0;
while(current != NULL && !found)
{
if(current->v == el)
{
if(previous == NULL)
{
backup = current->next;
free(current);
current = backup;
previous = current;
}
else
{
previous->next = current ->next;
free(current);
current = current->next;
}
found = 1;
}
else
{
previous = current;
current = current->next;
}
}
return backup;
}
void print(ll_node_ptr head)
{
ll_node_ptr current = head;
printf("%d\n", head->v);
while(current->next != NULL)
{
current = current->next;
printf("%d\n", current->v);
}
}
int isPair(int n)
{
return ((n % 2) == 0);
}
int main(int argc, char** argv)
{
int n = 1;
ll_node_ptr list = NULL;
while(n != 0)
{
scanf("%d", &n);
if(n < 0)
{
list = pop_el(list, -n);
}
else
{
if(isPair(n))
{
list = push_head(list, n);
}
else
{
list = push_tail(list, n);
}
}
}
print(list);
//should free the list
return 0;
}
应产生以下输出:
2
2
9
有什么线索吗?首先,我建议在处理列表时使用递归函数。它更容易调试和理解 我想我发现你的推尾功能有问题:
current->next = (ll_node_ptr) malloc(sizeof(ll_node));
current->v = v;
为当前->下一步分配内存,但将值分配给当前节点。
这应该是
current->next = (ll_node_ptr) malloc(sizeof(ll_node));
current->next->v = v;
current->next->next = NULL;
也许这与您的问题有关。首先,我建议在处理列表时使用递归函数。它更容易调试和理解 我想我发现你的推尾功能有问题:
current->next = (ll_node_ptr) malloc(sizeof(ll_node));
current->v = v;
为当前->下一步分配内存,但将值分配给当前节点。
这应该是
current->next = (ll_node_ptr) malloc(sizeof(ll_node));
current->next->v = v;
current->next->next = NULL;
也许这与你的问题有关。正如@Vitek所指出的,你眼前的问题可以通过修复
push\u tail()
函数来解决。原始代码不仅将值存储在错误的节点中,而且未能将新分配的尾部节点的next
字段设置为NULL
。此函数中还有一个问题:push\u head()
和push\u tail()
函数在使用NULL
head
指针调用时都需要创建并返回节点指针。原始的push\u head()
函数可以执行此操作,但是push\u tail()
函数不能执行此操作。如果用户输入的第一个数字是奇数,则通过push_tail()
函数将第一个节点添加到列表中,从而导致未定义的行为(很可能是分段错误)
更重要的是,您应该努力简化代码。这将使它更容易编写,也更容易调试。例如,print()
函数可以减少为三行:
void print(ll_node_ptr current)
{
while(current) {
printf("%d\n", current->v);
current = current->next;
}
}
要改进push\u tail()
功能,可以做几件事。以下是一个新版本:
ll_node_ptr push_tail(ll_node_ptr head, int v)
{
ll_node_ptr current = head;
ll_node_ptr prev = NULL;
ll_node_ptr tail = malloc(sizeof(ll_node));
if (tail == NULL) {
fprintf(stderr, "Tail node allocation error\n");
exit(EXIT_FAILURE);
}
tail->v = v;
tail->next = NULL;
while (current) {
prev = current;
current = current->next;
}
if (head) {
prev->next = tail;
} else {
head = tail;
}
return head;
}
您不需要强制转换malloc()
的结果,但是不使用cast编写代码简化了代码。此外,您应该检查以确保malloc()
已成功分配请求的内存。如果改用realloc()
,这一点尤其重要,因为如果不这样做,可能会导致内存泄漏。在此处创建新的尾部节点后,立即设置v
和next
字段
通过查看current
节点,而不是查看current->next
节点,在链表上迭代似乎更简单。使用prev
节点指针有助于实现这一点。新函数在列表上迭代,直到current==NULL
,此时prev
指向列表的最后一个节点。如果head
作为NULL
指针传入(即,列表为空,如果用户输入的第一个数字是奇数,则可能发生这种情况),则跳过迭代循环,因为current
初始化为head
。循环后的代码将最后一个节点的next
字段设置为指向新创建的尾部节点(如果函数具有非空列表),否则head
将成为新的尾部节点。最后,head
返回给调用函数
可以对pop_el()
函数进行许多简化,并且还有许多多余的代码。这个功能真的应该完全重新设计。如果您有:
previous->next = current ->next;
free(current);
current = current->next;
您将释放d当前引用的内存,然后尝试取消引用指向该内存的指针。在调用free()
后,您不再拥有此内存,并且这是。相反,您希望:
current = previous->next;
但这并不重要,因为found
下一步设置为1
,循环终止,函数返回sbackup
,不再使用current
。您只需将上述分配删除到current
,因为它不是必需的
您应该能够使用这些信息来改进程序中的其余代码。您可能还需要考虑其他问题。通常使用typedef
指针是一种不好的做法——这只会混淆代码,增加编程错误的可能性。您提供的规范没有明确说明如果有多个节点包含相同的值会发生什么情况,即是否应该删除一个或全部节点?而且,如果用户输入的第一个数字是0
?您眼前的问题可以通过修复@Vitek指出的push_tail()
函数来解决。原始代码不仅将值存储在错误的节点中,而且未能将新分配的尾部节点的next
字段设置为NULL
。此函数中还有一个问题:push\u head()
和push\u tail()
函数在使用NULL
head
指针调用时都需要创建并返回节点指针。原始的push\u head()
函数可以执行此操作,但是push\u tail()
函数不能执行此操作。如果用户输入的第一个数字是奇数,则第一个节点将通过<
else
{
previous->next = current ->next;
free(current);
//current = current->next; ---> Not needed.
break; // ---> No need of setting found flag. You can remove it
}
ll_node_ptr push_tail(ll_node_ptr head, int v)
{
ll_node_ptr backup = head;
ll_node_ptr current = head;
ll_node_ptr new = NULL; // Created new pointer
while(current->next != NULL)
{
current = current->next;
}
//current->next = (ll_node_ptr) malloc(sizeof(ll_node));
new = (ll_node_ptr) malloc(sizeof(ll_node));
//current->v = v; ----> incorrect. new Value is actually replacing the old value.
new->v = v; // New value is added in the newly created node.
new->next = NULL;
current->next = new;
return backup;
}
void print(ll_node_ptr head)
{
ll_node_ptr current = head;
//printf("%d\n", head->v);
while(current != NULL)
{
printf("%d\n", current->v);
current = current->next;
}
}