0

作成しているシェルのこのコードに取り組んでいますが、何らかの理由で機能していません。引数が指定されたときにユーザーを監視するwatchuser関数を実装しています(args [1])。ただし、「off」の2番目の引数(args [2])が指定された場合、ユーザーはリンクリストから削除され、監視されなくなります。

struct userList * goList;
goList = userInventory;
do{
    if (strcmp(userInventory->username, args[1]) == 0){              
       printf("%s\n", args[1]);
       printf("%s\n",userInventory->username);                      
       struct userList * temp2;
       temp2 = userInventory->next;
       if (userInventory->next != NULL){
          userInventory->next = temp2->next;
          userInventory->next->prev = userInventory;
       }                        
       free(temp2);
    }
    goList = goList->next;      
}while  (goList != userInventory);

私のグローバル構造体も次のとおりです。

struct userList{
    char * username;
    struct userList * prev;
    struct userList * next;
}

理由により、このコードはリンクリストからユーザーノードを削除しません。追加は機能しますが、この削除機能は機能せず、理由はわかりません。printステートメントは、条件を実行していることを確認するためだけにあります。

誰かが私のエラーの背後にある理由を見つけるのを手伝ってくれるなら、私はそれを大いに感謝します。それまでは、これをデバッグしようとしています。

ありがとう。

4

1 に答える 1

0

私があなたのコードについて何か理解しているなら、

問題1(もっともらしい):

goList = userInventory;
do {
    ...
    goList = goList->next;
} while (goList != userInventory);

これは循環リストですか?そうでない場合、の条件はwhile ()真になりません。

問題2:

goList = userInventory;
do {
    if (strcmp(userInventory->username, args[1]) == 0) {
    ...
    }
    goList = goList->next;
} while (goList != userInventory);

ここでは、現在のノードの文字列を比較する代わりに、リストの先頭(または末尾)の文字列を比較し続けますgoList。一致を見つけることは、一致が最初にuserInventory指す最初のノード(ヘッド/テール)にある場合にのみ、上記のコードで成功することができます。

問題3:

   temp2 = userInventory->next;
   if (userInventory->next != NULL) {
      userInventory->next = temp2->next;
      userInventory->next->prev = userInventory;
   }
   free(temp2);

userInventoryすでに次のように修正されていると仮定しましょうgoList

   temp2 = goList->next;
   if (goList->next != NULL) {
      goList->next = temp2->next;
      goList->next->prev = goList;
   }
   free(temp2);

まず第一に、それfree()は一致するノードではなく、その次のノード(またはおそらくNULL)に行きますが、これは間違っています。

第二に、このコードはノードの適切なリンク解除と再リンクを行っていません。それがどうあるべきか(リストが循環していないと仮定して):

   temp2 = goList;
   if (goList->next != NULL) {
      goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
   }
   if (goList->prev != NULL) {
      goList->prev->next = goList->next; // now goList->prev node points to goList->next node
   }
   free(temp2);

問題4:

do {
    if (strcmp(goList->username, args[1]) == 0) {
        temp2 = goList;
        if (goList->next != NULL) {
            goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
        }
        if (goList->prev != NULL) {
            goList->prev->next = goList->next; // now goList->prev node points to goList->next node
        }
        free(temp2);
    }
    goList = goList->next;
} while (...);

削除が成功すると、この行は解放されたばかりのノードにアクセスし、プログラムをクラッシュさせる可能性があります。

    goList = goList->next;

したがって、コードを次のように変更する必要があります。

do {
    if (strcmp(goList->username, args[1]) == 0) {
        temp2 = goList;
        if (goList->next != NULL) {
            goList->next->prev = goList->prev; // now goList->next node points to goList->prev node
        }
        if (goList->prev != NULL) {
            goList->prev->next = goList->next; // now goList->prev node points to goList->next node
        }
        goList = goList->next;
        free(temp2);
    }
    else
    {
        goList = goList->next;
    }
} while (...);

問題5:

goList = userInventory;

リストヘッド(またはテール?)ノードを削除した場合はuserInventory、その次のノードを指すように更新する必要があります。そうしuserInventoryないと、残りのノードが存在する場合ではなく、解放されたメモリを指すため、リストへのすべてのアクセスが失われます。

問題6(もっともらしい):

        free(temp2);

上記の行はfree()、背後のメモリではありませんtemp2->username。それが編集されfree()た場合、あなたはそれをしたいです。malloc()

実際には、一度に1ステップずつ問題に取り組む必要があります(たとえば、最初にリストを反復処理し、次にノードのリンク解除/再リンクを行い、次にノードを削除します)。

物事がはっきりしない、または機能していない場合は、紙と鉛筆(または製図板とペンまたはチョーク)を使用して、問題を自分で視覚化します。オブジェクト、ポインターまたはそれらの間のその他の接続を示す矢印などを描画し、オブジェクトの横に変数名を書き留めて、図からコードに進む方法を明確に確認できるようにします。

于 2012-10-23T04:57:42.420 に答える