2017-02-02 43 views
-1

我找不出问题出在哪里,C - 从单个链表中删除一个元素

为什么del函数不能按预期工作?

#include<stdio.h> 
#include<malloc.h> 

typedef struct list List; 

struct list 
{ 
    int data; 
    List* next; 
}; 

void prl(List* head); 
void ins(List** head, int value); 
void del(List** head, int value); 

int main() 
{ 
    List* head = NULL; 

    ins(&head, 10); 
    ins(&head, 50); 
    ins(&head, 20); 
    ins(&head, 150); 
    ins(&head, 120); 

    del(&head, 150); 

    prl(head); 

    //freeing dynamically allocated memory for each nodes 

    while(head!=NULL) 
    { 
     List* t = head; 
     head = head->next; 
     free(t); 
    } 

    return 0; 
} 

void prl(List* head) 
{ 
    if(head == NULL) 
     printf("List is empty\n"); 
    else 
    { 
     while(head != NULL) 
     { 
      printf("%d ", head->data); 
      head = head->next; 
     } 
    } 
} 

void ins(List** head, int value) 
{ 
    List* node = malloc(sizeof *node); 

    node->data = value; 
    node->next = NULL; 

    node->next =*head; 
    *head = node; 

} 


void del(List** head, int value) 
{ 
    List* p,*q; 
    p=q=*head; 

    if((*head)->data == value) 
    { 
     *head = (*head)->next; 
     free(p); 
     return; 
    } 
    else 
    { 
     while(p->next != NULL) 
     { 
      if(p->data == value) 
      { 
       q->next = p->next; 
       free(p); 
      } 
      else 
      { 
       q = p; 
       p = p->next; 
      } 
     } // while loop ends 

    } // outer else ends 

} // del function ends 

运行之后,输出是空白,我认为有些事情(逻辑)是错误的删除功能外其他循环内,但是第一个值可以使用此功能被删除。

+2

您是否尝试过通过调试器运行代码? –

+2

如果您之前没有使用调试器,现在是最佳时机。使用调试器,您可以逐行执行代码,同时监视变量及其值。你当然也可以在他们被调用时进入功能。当你有这样的问题时,你应该首先尝试使用调试器来尝试找出问题。 –

+0

为什么你的'del'函数只会删除该值的一个副本,如果它出现在列表的头部?但是,如果它不在列表的头部,它会迭代整个列表并尝试删除该值的所有副本? – Kaz

回答

1

我想你没有在这里加一个return语句:

if(p->data == value) 
    { 
     q->next = p->next; 
     free(p); 
     return; 
    } 
+1

这取决于他是要删除目标值的第一次出现还是全部。 –

+0

@JohnBollinger是的,你是对的,它正在修复删除第一次出现的目标值。 –

2

尽管我的评论,我决定帮助你。

让我们一起来看看这些行:

while(p->next != NULL) 
{ 
    if(p->data == value) 
    { 
     q->next = p->next; 
     free(p); 
    } 
    else 
    { 
     // Irrelevant... 
    } 
} 

比方说环路,p->data == value中的条件,恰好是真实的,那么会发生什么?你让q->next指向p->next,这可能是好的,然后你继续循环而不使p指向其他任何地方。

当循环继续时,p指向刚才调用free的数据,因此使用例如p来解除引用。 p->next在循环条件下将导致未定义的行为

解决方法是适当更新pq

+0

感谢让我容易理解,我认为使用'return;'语句正在解决我的问题(删除第一次出现),不是吗? –

+1

@someuser如果你只想删除第一个匹配元素,那么你应该返回(或至少退出循环)。 –