2017-04-20 53 views
1

我在使用此功能時遇到困難。 該功能應該搜索鏈接列表中的學生,並刪除此節點或打印錯誤消息(如果找不到該學生)。以下代碼無法正常工作,它會刪除正在搜索的節點之後的下一個節點。搜索並從鏈接列表中刪除

void vymazstudenta(STUDENT **head,const char *priezvisko) 
{ 
    STUDENT *traverse = *head; 
    while(traverse!=NULL) 
    { 
     if(!strcmp(traverse->priezvisko,priezvisko)) 
     { 
     STUDENT *hladany = traverse->next; 
     traverse->next = hladany->next; 
     free(hladany); 
     return; 
     } 
     traverse = traverse->next; 
    } 
     fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko); 
     return; 
} 
+3

原來這就是這個代碼在做什麼。你需要修復它。提示:保存先前掃描的節點。 –

+0

你說你的問題,它刪除下一個節點。您正在保存對下一個節點的引用,然後釋放它:'STUDENT * hladany = traverse-> next; ... free(hladany);' – BurnsBA

+0

爲什麼在沒有'malloc()'的時候,循環裏面有'free()'? –

回答

3

當遍歷你要存儲preceeds您檢查的一個節點列表(我用下面的代碼片段命名previous指針)。

當您找到匹配節點時,您只需將當前節點的前一個節點上的next設置爲當前節點的next,這樣該列表將跳過要刪除的節點。 然後你可以free()的匹配節點。

請注意,您應該處理的特殊情況要去除的節點是第一個(在head

在下面的代碼片段你看到這個在if(previous == NULL)塊 - 這是相當自我解釋。

void vymazstudenta(STUDENT **head,const char *priezvisko) 
{ 
    STUDENT *traverse = *head; 
    STUDENT *previous = NULL; 
    while(traverse != NULL) 
    { 
     if(strcmp(traverse->priezvisko,priezvisko) == 0) 
     { 
      if(previous == NULL) 
      { 
       *head = traverse->next; 
      } 
      else 
      { 
       previous->next = traverse->next; 
      } 
      free(traverse); 
      return; 
     } 
     else 
     { 
      previous = traverse; 
      traverse = traverse->next; 
     } 
    } 

    fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko); 
    return; 
} 
+0

或者只是雙用於提供給函數的'head'指針指針,並消除這段代碼的相當一部分。 [看到這裏的例子](https://pastebin.com/3BTKaBbM) – WhozCraig

+0

@WhozCraig我試着讓代碼類似於OP發佈的代碼片段,讓他更好地理解解決方案背後的邏輯。當然你的方法更加優雅。 – Paolo

+0

@ 4386427固定。謝謝! – Paolo

2

你需要保持元素的軌道前traverse這樣就可以改變該元素的下一指針traverse後指向元素。之後,您可以free(traverse)

此外,您需要處理一個特殊情況。那就是當比賽在*head元素上時。在這種情況下,您必須更新*head以獲得新的列表頭。

是這樣的:

void vymazstudenta(STUDENT **head,const char *priezvisko) 
{ 
    if (*head == NULL) 
    { 
     // empty list 
     return; 
    } 

    if(!strcmp(*head->priezvisko,priezvisko)) 
    { 
     // Special case: 
     // Remove the *head element 

     STUDENT *hladany = *head; // Save a pointer to current head 
     *head = *head->next;  // Update head 
     free(hladany);    // Free the previous head 
     return; 
    } 

    STUDENT *traverse = *head->next; 
    STUDENT *previous = *head; 

    while(traverse!=NULL) 
    { 
     if(!strcmp(traverse->priezvisko,priezvisko)) 
     { 
      previous->next = traverse->next; // Update previous to point 
               // to element after traverse. 

      free(traverse);     // Now free traverse 
      return; 
     } 

     previous = traverse;     // Move previous to next element 
     traverse = traverse->next;   // Move traverse to next element 
    } 

    fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko); 
    return; 
} 
1

功能是錯誤的,至少因爲它忽略的情況下,當報頭滿足條件。

此外,你應該保留在刪除節點之前的節點。

功能可以看看下面的方式

void vymazstudenta(STUDENT **head, const char *priezvisko) 
{ 
    STUDENT *tmp = NULL; 

    if (*head != NULL) 
    { 
     if (strcmp(head->priezvisko, priezvisko) == 0) 
     { 
      tmp = *head; 
      *head = (*head)->next; 
     } 
     else 
     {   
      STUDENT *traverse = *head; 
      while(traverse->next != NULL && strcmp(traverse->next->priezvisko, priezvisko) != 0) 
      { 
       traverse = traverse->next; 
      } 

      if (traverse->next != NULL) 
      { 
       tmp = traverse->next; 
       traverse->next = traverse->next->next; 
      } 
     } 
    } 

    if (tmp != NULL) 
    { 
     free(tmp); 
    } 
    else 
    { 
     fprintf(stderr, "Student %s sa nenasiel.\n", priezvisko); 
    } 
}