2017-02-02 111 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如果你只想刪除第一個匹配元素,那麼你應該返回(或至少退出循環)。 –