- ベストアンサー
リストの削除について(構造体)
- リストの削除のプログラムを実行して行うと、リストの削除処理中に問題が発生し、変更後の処理が正しく表示されません。
- どこが間違っているかが分からず、解決方法を求めています。
- プログラムの内容を要約すると、構造体を使用してリストを作成し、指定されたキーに一致する要素を削除する処理を行っています。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
なるべく原型のままで修正するとこんな感じでしょうか。 printf("削除key入力(name)\n"); gets(key); n = head; while(n != NULL){ old = n; n = n -> next; if (n == NULL) break; //printf("n -> name %s\n", n -> name); if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); //printf("n -> name %s old -> name %s\n", n -> name, old -> name); old -> next = n -> next; free(n); n=old; /* 次のnはold変えずにもう一度 */ } } 最後に後始末いれるとしたら、 /* head含めて全部解放 */ p = head; while (p != NULL) { n=p; p=p->next; free(n); } ちなみに、while(n -> next != NULL){ とやってしまうと、最後の要素を見なくなるんじゃ?
その他の回答 (2)
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
printf("削除key入力(name)\n"); gets(key); n = head;// ヘッダから初めてはダメですよね。ダミーなんですから。他と同じようにしないとね。 while(n != NULL){ old = n; // 今このnが消したいnの時oldにnをいれてうまくいくでしょうか? n = n -> next; if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); old -> next = n -> next; //切り離したnが解放されていません。 } } //------------------------------------------ まず、おかしい所をなおしてからじゃないと次に進めないのでとりあえず、上記の部分を指摘しておきます。
お礼
調べてみましたところ、free(n)の後の処理でn -> nextにはNULLは格納されているようでwhile(n -> next != NULL){の処理でうまく終わるようです。 1件目の削除する場合は、n = n -> next;で先ほど挙げたようにNULLがnに入った事により関数を呼び出したことでお陀仏をいう有り様だという結論です。 どうも、私の疑問に付き合ってくださってありがとうございます。
補足
返答ありがとうございます。 まず、はじめに質問した「リストの削除処理中にプログラムが終わって変更後処理がうまく表示されません。」というものですが、if(strcmp(n -> name, key) == 0){ の処理の部分で最終的にnの中に格納されているのがNULLなので関数を呼び出したときに処理が終わってしまうようです。実際簡単なプログラムを使って実験してみました。 あと私のプログラムがうまく動かない原因の箇所はひとつだけで、while(n != NULL){では先ほど上に記述したように関数が呼び出したときに処理が終わるので、対策としてwhile(n -> next != NULL){に変更しました。 BLUEPIXYさんがいう、free(n)を実行することによって領域を解放することを知りましたが、私のソースで2件入力したときに1件目を削除したときは処理が途中で終了し、2件目を削除したときは最後までうまくいく原因が分かりません。2件目を削除したとき、while(n -> next != NULL){の処理できちんと終了するのが疑問です。1件目を削除したときはold = nなどの処理がうまくいかないのは想像できます。当然、free(n)の処理がなければどちらもうまくいきます。 返答のほどよろしくお願いいたします。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
直した処を下記に書きます。 参考にして下さい。 n = head->next; while(n != NULL){ p=n->next; // p は、テンポラリ if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); if(n==head->next){ //先頭が消されることもある。 head->next = p; } else { old -> next = p; } free(n); //削除したら解放しておく } else { old = n; } n = p; //次のループの準備 }
補足
返答ありがとうございます。 早速試してみましたところ、うまくいきました。 しかし、私のソースで何故だめなのかが分かりません。 返答のほどよろしくお願いいたします。
補足
free(n)のあとにn=oldにすればn != NULLの処理もきちんとできますね。原型のまま修正していただいてありがとうございます。 >while(n -> next != NULL){ とやってしまうと、最後の要素を見なくなるんじゃ? という質問をなさっていますが、3件入力したときにwhile(n -> next != NULL){ のn -> nextが3件目のポインタをさすとします。つまりnは2件目のデータをさします。その下の行でold = n;//2件目のポインタoldへ格納、n = n -> next//3件目のポインタnへ格納となり、3件目の処理ができます。よって最後の要素も処理がきちんとできるしだいです。 (下記ソース参照) while(n -> next != NULL){ old = n; n = n -> next; //printf("n -> name:%s\n", n -> name); if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); //printf("n -> name %s \n", n -> name); old -> next = n -> next; } }