C – 删除双向链表中的节点

当我尝试使用deleteinst方法删除列表中的每个其他元素时,该方法对链表没有任何作用,并且没有错误。 我真的不确定为什么它不起作用我已经看到了在不同程序中使用的相同deleteinst方法。 也许它与指针有关。 如果我运行deleteInst(track.prev,&head); 如果没有while循环,列表仍保持不变。

如果您有任何想法或需要更多信息,请告诉我。 感谢您的时间。

int main() { node *head; node *track; head = ReadNodeList(stdin); track = LastNode(head); //goes to last node. while(track != NULL){ int i=0; //delete every other node if(i%2 == 1){ deleteInst(track, &head); } i++; track = track->prev; } } void deleteInst(Instruction *victim, Instruction **head){ if(*head == NULL || victim == NULL) return; if(*head == victim) *head = victim->next; if(victim->next != NULL) victim->next->prev = victim->prev; if(victim->prev != NULL) victim->prev->next = victim->next; free(victim); return; } 

一个明显明显的问题是:你真的不想这样做:

  deleteInst(track, &head); track = track->prev; 

您释放该节点的那一刻,您将失去访问其成员的权利。 首先保存,然后在删除后恢复:

  node *save_prev = track->prev; deleteInst(track, &head); track = save_prev; 

我要检查的另一件事是列表结构是正确的,例如(仅在调试期间):

 static void checkList (node *curr) { int count = 0; // PreCon: head->prev must be null. if (curr != NULL) { if (curr->prev != NULL) { puts ("Linked list structure error A!"); exit (1); } } // Check all nodes. while (curr != NULL) { // PreCon: curr->prev->next must be curr. if (curr->prev != NULL) { if (curr->prev->next != curr) { puts ("Linked list structure error B!"); exit (1); } } // PreCon: curr->next->prev must be curr. if (curr->next != NULL) { if (curr->next->prev != curr) { puts ("Linked list structure error C!"); exit (1); } } // Move to next and keep count. curr = curr->next; count++; } // All okay, output success message with size. printf ("Linked list structure okay, size = %d\n", count); } 

使用checkList (head)调用它将validation您的链表是否满足所有有效性前提条件,因为您可能在其他地方有错误代码,例如在ReadNodeList()创建列表时。


除此之外我建议在ReadNodeList()之后单步执行IDE或调试器中的代码,看看它实际上在做什么。 并且,如果您没有IDE /调试器,请使用以下行代码来源代码:

 printf ("DEBUG %d: track = %p\n", __LINE__, track); 

然后检查调试语句的输出以分析程序中的流程。


现在,如果你真的要做那个调试练习,你可能会惊讶地发现deleteInst似乎永远不会被调用,因为i似乎总是设置为0

这个小问题的错误在于:

 while (track != NULL) { int i = 0; // <<<<<<< //delete every other node if (i%2 == 1) { deleteInst (track, &head); } i++; track = track->prev; } 

是的,没错,你通过循环每次都将i设置为0 因此i % 2永远不会等于1 。 您需要在循环之前初始化i (并且还会删除访问释放的内存的未定义行为):

 int i = 0; while (track != NULL) { node *save_prev = track->prev; //delete every other node if (i%2 == 1) deleteInst (track, &head); i++; track = save_prev; } 

如果在列表初始化期间将尾部放在列表上,则双链表更容易使用。 这消除了大多数令人头脑麻木的角落情况。

 #include  #include  typedef struct node { struct node *next; struct node *prev; int data; } node; void ShowList( node *head ); void AppendNodeWithData( node *tail, int data ); void RemoveNode( node *item ); int main( void ) { int i; node *head, *tail, *item, *temp; // allocate and initialize the doubly linked list head = malloc( sizeof(node) ); tail = malloc( sizeof(node) ); if ( !head || !tail ) exit( 1 ); head->next = tail; head->prev = NULL; tail->next = NULL; tail->prev = head; // add some items to the list for ( i = 0; i < 20; i++ ) AppendNodeWithData( tail, i ); ShowList( head ); // remove every other item for ( item = tail->prev; item != NULL && item->prev != NULL; item = temp ) { temp = item->prev->prev; RemoveNode( item ); } ShowList( head ); } void ShowList( node *head ) { node *item; for ( item = head->next; item->next != NULL; item = item->next ) printf( " %d", item->data ); printf( "\n" ); } void AppendNodeWithData( node *tail, int data ) { node *item; if ( (item = malloc( sizeof(node) )) == NULL ) exit( 1 ); item->data = data; item->prev = tail->prev; item->next = tail; tail->prev->next = item; tail->prev = item; } void RemoveNode( node *item ) { item->next->prev = item->prev; item->prev->next = item->next; free( item ); }