在学校的项目中,我发现了一个小问题,我不知道如何解决。 问题出在clear_train 上。当我尝试删除 1. 元素时,函数也返回我的元素(但为空)。 这是我的源代码,其中是所有函数的定义: (a_train.h中是函数的声明和描述)
#include "a_train.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct car* add_car(struct car* first,const char* target) {
struct car* adder = malloc(sizeof(struct car));
struct car *current = first;
strcpy (adder->value,target);
adder->next=NULL;
if(first == NULL){
first =adder;}
else{
while (current->next != NULL) {
current = current->next;
}
current->next = adder;
}
return first ;
}
void print_train(struct car* first) {
if (first!=NULL){
while (first!=NULL){
printf("%s\n",first->value);
first=first->next;
}
}
else printf("empty list\n");
}
void cancel_train(struct car* first) {
while(first!=NULL){
struct car* canceler = first->next;
free(first);
first=canceler;
}
}
struct car* clear_train(struct car* first, const char* target) {
if(first == NULL){
return NULL;
}else if (first->next==NULL){
if(strcmp(first->value,target)==0){
free(first);
return NULL;
}else return first;
}
struct car* prev_searcher =first;
struct car* this_searcher =first;
while (this_searcher!=NULL){
if(strcmp(this_searcher->value,target)==0){
prev_searcher->next=this_searcher->next;
free(this_searcher);
}
prev_searcher=this_searcher;
this_searcher=this_searcher->next;
}
return first;
}
这是链表的定义:
struct car {
char value[SIZE];
struct car* next;
};
我调用函数的主要源代码:
int main(){
struct car* train = NULL;
train = add_car(train,"Presov");
train = add_car(train,"Bratislava");
train = add_car(train,"Levoca");
train = add_car(train,"Spiska Nova Ves");
train = add_car(train,"Bardejov");
train = add_car(train,"Pichne");
clear_train(train,"Presov");
print_train(train);
cancel_train(train);
return 0;
}
最后有输出:
//there is empty node
Bratislava
Levoca
Spiska Nova Ves
Bardejov
Pichne
最佳答案
从链表中删除节点变得比实际需要的更加困难。虽然每次调用 clear_train
时您都可以自由地返回并分配头节点,但这并不是真正的方法。
不要将指向头的指针(first
)作为参数传递给clear_train
,而是传递头指针的实际地址,例如
clear_train(&train,"Presov");
这样你就可以直接操作该地址处的值(节点)。如果列表中的第一个节点是要删除的节点,则只需将原始指针保存的节点地址更新为新的第一个节点即可。
无需尝试保留上一个、当前和下一个节点,只需使用指向当前节点的指针即可。然后,当找到包含 target
的节点时,只需将该地址处的指针更新为 ->next
节点即可。请参阅Linus on Understand Pointers
这会将您的 clear_train
函数简化为:
void clear_train (struct car **first, const char* target) {
struct car **ppn = first; /* pointer-to-pointer to first */
struct car *pn = *first; /* pointer-to-first */
for (; pn; ppn = &pn->next, pn = pn->next) { /* iterate, find target */
if (strcmp (pn->value, target) == 0) { /* if found */
*ppn = pn->next; /* set pointer at target address = next */
free (pn); /* free node contianing target */
break;
}
}
}
比尝试测试节点所在位置的不同情况简单得多。
关于c - 为什么我的所选元素的清除功能无法正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58780881/