2016-04-30 15 views
-2

現在、二重リンクリストからノードを削除しようとしていますが、1つのアイテムしか残されていない場合、行11で削除しようとするとアクセス違反例外がスローされます。(*sPtr)->prevPtr = NULL;二重リンクリストからノードを削除する方法

char del(ListNodePtr *sPtr, char value) 
{ 
    ListNodePtr previousPtr; /* pointer to previous node in list */ 
    ListNodePtr currentPtr; /* pointer to current node in list */ 
    ListNodePtr tempPtr; /* temporary node pointer */ 

    /* delete first node */ 
    if (value == (*sPtr)->data) { 
     tempPtr = *sPtr; /* hold onto node being removed */ 
     *sPtr = (*sPtr)->nextPtr; /* de-thread the node */ 
     (*sPtr)->prevPtr = NULL; 
     if ((*sPtr)->nextPtr != NULL) { 
      free(tempPtr); /* free the de-threaded node */ 
     } 
     return value; 
    } /* end if */ 
    else { 
     previousPtr = *sPtr; 
     currentPtr = (*sPtr)->nextPtr; 

     /* loop to find the correct location in the list */ 
     while (currentPtr != NULL && currentPtr->data != value) { 
      previousPtr = currentPtr; /* walk to ... */ 
      currentPtr = currentPtr->nextPtr; /* ... next node */ 
     } /* end while */ 

      /* delete node at currentPtr */ 
     if (currentPtr != NULL) { 
      tempPtr = currentPtr; 
      previousPtr->nextPtr = currentPtr->nextPtr; 
      free(tempPtr); 
      return value; 
     } /* end if */ 
    } /* end else */ 

    return '\0'; 
} 

EDIT:これは私の現在の削除機能である私は、私は私の質問を再度開くことができるようにやろうとしています何のより良い状況については、以下の順に私の主な機能と私の印刷機能を追加するつもりです。ここ

は私のlistNode構造体と私の主な機能です:

struct listNode { 
    char data; /* each listNode contains a character */ 
    struct listNode *nextPtr; /* pointer to next node*/ 
    struct listNode *prevPtr; /* pointer to previous node*/ 
}; /* end structure listNode */ 

typedef struct listNode ListNode; /* synonym for struct listNode */ 
typedef ListNode *ListNodePtr; /* synonym for ListNode* */ 

     /* prototypes */ 
void insert(ListNodePtr *sPtr, char value); 
char del(ListNodePtr *sPtr, char value); 
int isEmpty(ListNodePtr sPtr); 
void printList(ListNodePtr currentPtr); 
void printReverse(ListNodePtr currentPtr); 
void instructions(void); 

int main(void) 
{ 
    ListNodePtr startPtr = NULL; /* initially there are no nodes */ 
    int choice; /* user's choice */ 
    char item; /* char entered by user */ 

    instructions(); /* display the menu */ 
    printf("? "); 
    scanf("%d", &choice); 

    /* loop while user does not choose 3 */ 
    while (choice != 3) { 

     switch (choice) { 
     case 1: 
      printf("Enter a character: "); 
      scanf("\n%c", &item); 
      insert(&startPtr, item); /* insert item in list */ 
      printList(startPtr); 
      printReverse(startPtr); 
      break; 
     case 2: 
      /* if list is not empty */ 
      if (!isEmpty(startPtr)) { 
       printf("Enter character to be deleted: "); 
       scanf("\n%c", &item); 

       /* if character is found, remove it */ 
       if (del(&startPtr, item)) { /* remove item */ 
        printf("%c deleted.\n", item); 
        printList(startPtr); 
        printReverse(startPtr); 
       } /* end if */ 
       else { 
        printf("%c not found.\n\n", item); 
       } /* end else */ 
      } /* end if */ 
      else { 
       printf("List is empty.\n\n"); 
      } /* end else */ 

      break; 
     default: 
      printf("Invalid choice.\n\n"); 
      instructions(); 
      break; 
     } /* end switch */ 

     printf("? "); 
     scanf("%d", &choice); 
    } /* end while */ 

    printf("End of run.\n"); 
    return 0; /* indicates successful termination */ 
} /* end main */ 

、ここでは私のprintReverseとがprintlist関数です:

void printList(ListNodePtr currentPtr) 
{ 

    /* if list is empty */ 
    if (currentPtr == NULL) { 
     printf("List is empty.\n\n"); 
    } /* end if */ 
    else { 
     printf("The list is:\n"); 

     /* while not the end of the list */ 
     while (currentPtr != NULL) { 
      printf("%c --> ", currentPtr->data); 
      currentPtr = currentPtr->nextPtr; 
     } /* end while */ 

     printf("NULL\n\n"); 
    } /* end else */ 
} /* end function printList */ 

void printReverse(ListNodePtr currentPtr) 
{ 
    /* if list is empty */ 
    if (currentPtr == NULL) { 
     printf("List is empty.\n\n"); 
    } /* end if */ 
    else { 
     printf("The list in reverse is:\n"); 

     while (currentPtr->nextPtr != NULL) 
      currentPtr = currentPtr->nextPtr; 

     /* while not the beginning of the list */ 
     while (currentPtr != NULL) { 
      printf("%c --> ", currentPtr->data); 
      currentPtr = currentPtr->prevPtr; 
     } /* end while */ 

     printf("NULL\n\n"); 
    } /* end else */ 
} /* end function printList */ 

私はこれが最後の3日間このことに固執していて、私がやっていることをやり遂げる方法についてオンラインで見つけることができるトピックはほとんどないので、これは、リストが挿入と削除の際にアルファベット順にソートされるためです。

誰かが何が間違っているのかを教えてもらえれば、リストの最後の項目を削除しようとするとアクセス違反例外が11行目にスローされます。ありがとう!

+1

にチェックマークが付いていない、それはおそらくですので、 '(* SPTR) - * sPtr''にassingedさ> nextPtr'が、あった 'NULL'一つのノードのみが残っているので。 – MikeCAT

+0

@MikeCATどこで解決するのですか? –

+0

ヘッド(単一リンクリストの場合)とテール(両方とも二重リンクリストの場合)ポインタがない場合、私はそれらを強くお勧めします。私は誰もそれらなしでリンクされたリストをどのようにしているのか分かりません。ノードの挿入と削除は、リスト内に0または1の要素がある場合は特殊なケースです。ヘッドとテールポインタを保持すると、はるかに簡単です。私は誰かがここで誰かが空想を得ることができ、それらなしでリンクされたリストを行うことができると言っているが。 – yano

答えて

0

あなたは物事が複雑すぎると思います。あなたは "ノード"型から "リスト"型を分離しませんが、私はあなたが単に置換を返す場合は、ポインタへのポインタを渡さずに得ることができると思います。

文字をルックアップしてそのノードへのポインタを返す処理を行うための "find"メソッドを記述したいと思うかもしれません。

/** 
    Delete the node containing value from the list starting with start. 
    If value is not found in list, then the list is unchanged. Returns 
    a replacement value for start, which may be needed if the value is 
    contain in the start node. 
*/ 

ListNodePtr del(ListNodePtr start, char value) 
{ 
    ListNodePtr curr; 

    for (curr = start; curr && curr->data != value; curr = curr->nextPtr) { 
     // skip this node 
    } 

    if (!curr) { 
     // Value not found in list. List is unchanged. 
     return start; 
    } 

    /* Compute return value */ 

    if (curr == start) { 
     start = start->nextPtr; 
    } 

    /* Remove curr node from chain */ 

    if (curr->prevPtr) { 
     curr->prevPtr->nextPtr = curr->nextPtr; 
    } 

    if (curr->nextPtr) { 
     curr->nextPtr->prevPtr = curr->prevPtr; 
    } 

    free(curr); 
    return start; 
} 
0

私は私の問題を実現しました。 Visual Studioではブレークポイントを使用させていませんでしたが、それは「デバッグ」ではなく「リリース」に設定していたことがわかっていなかったためです。

/* Delete a list element */ 
char del(ListNodePtr *sPtr, char value) 
{ 
    ListNodePtr previousPtr; /* pointer to previous node in list */ 
    ListNodePtr currentPtr; /* pointer to current node in list */ 
    ListNodePtr tempPtr; /* temporary node pointer */ 

    /* delete first node */ 
    if (value == (*sPtr)->data) { 
      tempPtr = *sPtr; /* hold onto node being removed */ 
      *sPtr = (*sPtr)->nextPtr; /* de-thread the node */ 
      if(*sPtr != NULL) /* if the list is not empty */ 
       (*sPtr)->prevPtr = NULL; /* the previos pointer is null*/ 
      free(tempPtr); /* free the de-threaded node */ 
      return value; 
    } /* end if */ 
    else { 
     previousPtr = *sPtr; 
     currentPtr = (*sPtr)->nextPtr; 

     /* loop to find the correct location in the list */ 
     while (currentPtr != NULL && currentPtr->data != value) { 
      previousPtr = currentPtr; /* walk to ... */ 
      currentPtr = currentPtr->nextPtr; /* ... next node */ 
     } /* end while */ 

      /* delete node at currentPtr */ 

     if (currentPtr != NULL) { 
      tempPtr = currentPtr; 
      previousPtr->nextPtr = currentPtr->nextPtr; 
      if(previousPtr->nextPtr != NULL) /* if the next pointer isn't null */ 
       previousPtr->nextPtr->prevPtr = currentPtr->prevPtr; /* the previous pointer of the next pointer is the previous pointer of the current pointer */ 
      free(tempPtr); 
      return value; 
     } /* end if */ 

    } /* end else */ 
    return '\0'; 
} /* end function delete */ 
1

あなたのコードは、新しいヘッドノードが最後の削除後にnullであるかどうかをチェックしません。だから私は、彼らがリンクになったり、間違ったものにリンクされ、この解決策を考え出した場所を把握するためにポインタを追跡することをやってしたがって、ヘッドノードの次のポインタをnullに設定しようとすると、コードがクラッシュします。

固定コード(valgrind下で漏れのないとエラーフリーを実行):

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 

struct listNode 
{ 
    char data; 
    struct listNode *nextPtr; 
    struct listNode *prevPtr; 
}; 

typedef struct listNode ListNode; 
typedef ListNode *ListNodePtr; 

void insert(ListNodePtr *sPtr, char value); 
char del(ListNodePtr *sPtr, char value); 
int isEmpty(ListNodePtr sPtr); 
void printList(ListNodePtr currentPtr); 
void printReverse(ListNodePtr currentPtr); 

static void ins_check(ListNode **list, char c) 
{ 
    printf("Inserting [%c] (%p)\n", c, (void *)*list); 
    insert(list, c); 
    printList(*list); 
    printReverse(*list); 
} 

static void del_check(ListNode **list, char c) 
{ 
    printf("Deleting [%c] (%p)\n", c, (void *)*list); 
    if (del(list, c) != c) 
     printf("Did not find [%c] in list.\n", c); 
    printList(*list); 
    printReverse(*list); 
} 

int main(void) 
{ 
    ListNodePtr startPtr = NULL; 

    printList(startPtr); 
    printReverse(startPtr); 

    ins_check(&startPtr, 'a'); 
    ins_check(&startPtr, 'b'); 
    ins_check(&startPtr, 'c'); 

    del_check(&startPtr, 'c'); 
    del_check(&startPtr, 'a'); 
    del_check(&startPtr, 'b'); 

    assert(startPtr == 0); 

    printf("End of run.\n"); 
    return 0; 
} 

void printList(ListNodePtr currentPtr) 
{ 
    if (currentPtr == NULL) 
     printf("List is empty.\n"); 
    else 
    { 
     printf("The list is: "); 
     while (currentPtr != NULL) 
     { 
      printf("%c --> ", currentPtr->data); 
      currentPtr = currentPtr->nextPtr; 
     } 
     printf("NULL\n"); 
    } 
} 

void printReverse(ListNodePtr currentPtr) 
{ 
    if (currentPtr == NULL) 
     printf("List is empty (even in reverse).\n"); 
    else 
    { 
     printf("The list in reverse is: "); 
     while (currentPtr->nextPtr != NULL) 
      currentPtr = currentPtr->nextPtr; 
     while (currentPtr != NULL) 
     { 
      printf("%c --> ", currentPtr->data); 
      currentPtr = currentPtr->prevPtr; 
     } 
     printf("NULL\n"); 
    } 
} 

char del(ListNodePtr *sPtr, char value) 
{ 
    ListNodePtr previousPtr; 
    ListNodePtr currentPtr; 
    ListNodePtr tempPtr; 

    assert(*sPtr != 0); 
    if (value == (*sPtr)->data) 
    { 
     tempPtr = *sPtr; 
     printf("Deleting 1: [%c] (node = %p, next = %p, prev = %p\n", tempPtr->data, 
       (void *)tempPtr, (void *)tempPtr->nextPtr, (void *)tempPtr->prevPtr); 
     *sPtr = (*sPtr)->nextPtr; 
     if (*sPtr != 0) // Crucial change! 
      (*sPtr)->prevPtr = NULL; 
     free(tempPtr); 
     return value; 
    } 
    else 
    { 
     previousPtr = *sPtr; 
     currentPtr = (*sPtr)->nextPtr; 

     while (currentPtr != NULL && currentPtr->data != value) 
     { 
      previousPtr = currentPtr; 
      currentPtr = currentPtr->nextPtr; 
     } 

     if (currentPtr != NULL) 
     { 
      assert(previousPtr != 0); 
      tempPtr = currentPtr; 
      printf("Deleting 2: [%c] (node = %p, next = %p, prev = %p\n", tempPtr->data, 
        (void *)tempPtr, (void *)tempPtr->nextPtr, (void *)tempPtr->prevPtr); 
      previousPtr->nextPtr = currentPtr->nextPtr; 
      free(tempPtr); 
      return value; 
     } 
     else 
      printf("Did not find [%c]\n", value); 
    } 

    return '\0'; 
} 

void insert(ListNode **list, char value) 
{ 
    ListNode *node = malloc(sizeof(*node)); 
    if (node == 0) 
    { 
     fprintf(stderr, "Out of memory\n"); 
     exit(EXIT_FAILURE); 
    } 
    node->data = value; 
    node->nextPtr = 0; 
    node->prevPtr = 0; 
    if (*list != 0) 
    { 
     node->nextPtr = *list; 
     assert((*list)->prevPtr == 0); 
     (*list)->prevPtr = node; 
    } 
    *list = node; 
} 

例ラン:

List is empty. 
List is empty (even in reverse). 
Inserting [a] (0x0) 
The list is: a --> NULL 
The list in reverse is: a --> NULL 
Inserting [b] (0x7fccc3503070) 
The list is: b --> a --> NULL 
The list in reverse is: a --> b --> NULL 
Inserting [c] (0x7fccc3503090) 
The list is: c --> b --> a --> NULL 
The list in reverse is: a --> b --> c --> NULL 
Deleting [c] (0x7fccc35030b0) 
Deleting 1: [c] (node = 0x7fccc35030b0, next = 0x7fccc3503090, prev = 0x0 
The list is: b --> a --> NULL 
The list in reverse is: a --> b --> NULL 
Deleting [a] (0x7fccc3503090) 
Deleting 2: [a] (node = 0x7fccc3503070, next = 0x0, prev = 0x7fccc3503090 
The list is: b --> NULL 
The list in reverse is: b --> NULL 
Deleting [b] (0x7fccc3503090) 
Deleting 1: [b] (node = 0x7fccc3503090, next = 0x0, prev = 0x0 
List is empty. 
List is empty (even in reverse). 
End of run. 

注ラッパー関数(ins_check()del_check())の使用および使用固定データを簡単にテストすることができます(入力不要)。また、何が起こっているのかを記録してください。その機能を提供しているだろう真MCVE(How to create a Minimal, Complete, and Verifiable Example?)またはSSCCE(Short, Self-Contained, Correct Example) - 私は願っています

はあなたのinsert()は、私が考案したものと似ています。

「新しい」コードは、Is it a good idea to typedef pointersで示唆されている構造に従うことに注意してください。簡潔な答えは「非」(不透明でないデータポインタの場合)です。

削除機能は単一リンクリストの場合と同じくらい複雑ですが、二重リンクリスト内の各ノードはそれぞれの前任者を知っているため、はるかに簡単です。このバージョンはまた、きれいに動作します:

char del(ListNodePtr *sPtr, char value) 
{ 
    assert(*sPtr != 0); 
    ListNode *curr = *sPtr; 
    while (curr != NULL) 
    { 
     if (curr->data == value) 
     { 
      if (curr->prevPtr != NULL) 
       curr->prevPtr->nextPtr = curr->nextPtr; 
      if (curr->nextPtr != NULL) 
       curr->nextPtr->prevPtr = curr->prevPtr; 
      if (*sPtr == curr) 
       *sPtr = curr->nextPtr; 
      free(curr); 
      return value; 
     } 
     curr = curr->nextPtr; 
    } 

    printf("Did not find [%c]\n", value); 
    return '\0'; 
} 
関連する問題