質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

3016閲覧

リストのコードでfree()関数がよくわからない

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2018/01/18 09:42

自己参照構造体を使ったリスト処理コードでfree()関数のところが
よく理解できないので、おしえてください。
void free_list(struct list *p)でどうしてp2を定義するのか。
p2 = p->next;をどうして保存するのか。保存したp->nextをどうしてpに
設定しなおしているのか。この関数自体がなぜこんなことをしているのか分かりません。
自分ではp2はpをフリーする前に保存しておかないとfree(p);の後では
p = p2;が実行できないからだと思っています。

コード #include <stdio.h> #include <string.h> #include <stdlib.h> struct list { int key; // キー char name[20]; // 名前 struct list *next; // 次のデータへのポインタ }; struct list *add_list(int key, char *name, struct list *head); void show_list(struct list *p); void free_list(struct list *p); int main(void) { struct list *head; // 先頭ポインタ char name[20]; int key = 0; head = NULL; // 先頭ポインタにNULLを設定 printf("キーと名前(MAX:19文字)を入力(終了:CTRL+Z)\n"); while (scanf("%d %s", &key, name) != EOF) { head = add_list(key, name, head); // リストにデータを登録 } show_list(head); // リストの表示 free_list(head); // リストの開放 return 0; } // リストにデータを登録 struct list *add_list(int key, char *name, struct list *head) { struct list *p; // 記憶領域の確保 if ((p = (struct list *) malloc(sizeof(struct list))) == NULL) { printf("malloc error\n"); exit(EXIT_FAILURE); } // リストにデータを登録 p->key = key; strcpy(p->name, name); // ポインタのつなぎ換え p->next = head; // 今までの先頭ポインタを次ポインタに // 新しいデータの次のポインタに headのアドレスをつなぐ。 // p->nextが次を指すようにする。新たな領域を先頭ポインタに head = p; // 新たな領域を先頭ポインタに // headにpのアドレスを代入してpを先頭ポインタにする。 // 先頭ポインタ(head)新しくなったNODEに沿って移動していく return head; // 最後に代入されたデータがheadになるのでそのアドレスを返す。 } // リストの表示 void show_list(struct list *p) { while (p != NULL) { // 次ポインタがNULLまで処理 printf("%3d %s\n", p->key, p->name); p = p->next; } } //リストの開放 void free_list(struct list *p) { struct list *p2; while (p != NULL) { // 次ポインタがNULLまで処理 p2 = p->next; free(p); p = p2; } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

free(p)するとpにあるデータが読めないのでp->nextができなくなります。
一般的に、free(p)するとp=~を実行するまでpの使用ができなくなると覚えておくといいかと。

C

1 2// pは一つのリストの先頭の要素のメモリー上の位置を表す 3// 位置pから始まるリストを捨てる関数 4void free_list(struct list *p) 5{ 6 // p2は一つのリストの次の要素の位置のバックアップを表す 7 struct list *p2; 8 9 // 先頭の要素の位置pがNULLでない間、以下の処理を繰り返す 10 while (p != NULL) { 11 // 位置pにある要素から次の要素の位置をコピーしてp2に保存しておく 12 // (先頭の要素が最後の要素の時は次の要素の位置としてNULLがコピーされる) 13 p2 = p->next; 14 // 位置pにある要素を捨てる 15 free(p); 16 // 先頭の要素の位置pへ取っておいた次の要素の位置p2をコピーする 17 p = p2; 18 } 19}

投稿2018/01/18 10:32

編集2018/01/18 10:34
colonq

総合スコア88

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/18 10:43

早速回答していただきありがとうございます。先頭アドレスを次のデータにするために保存しておくためでいいですか。リストが辿れなくなるからですよね。
shsh_

2018/01/18 10:51

違います。 free(p)をしてポインタpが指すメモリを解法した後は、そのメモリの内容は不定になるため、読み書きすべきではないからです。 ```C /* 警告:このコードは間違い */ free(p); p = p->next; /* ポインタpが指す解放済みのメモリにあるp->nextを読んでいる */ ``` 上記のようなコードを書いてしまうと、大抵の場合は問題なく動くのにときどき予想しない動きをする、という厄介なバグの原因となります。
退会済みユーザー

退会済みユーザー

2018/01/18 11:00

ありがとうございます。void free_list(struct list *p)はいらなくて、free(p);だけでいいのですか。
colonq

2018/01/18 13:26

そうじゃないです。free_listは必要です。 例え話にすると右手p左手p2として p2 = p->next; free(p); p = p2; 「右手の上に書かれた住所に行って、そこにある手紙に書かれた住所を左手の上に書け」 「右手の上に書かれた住所に行って、そこを爆破せよ」 「左手の上に書かれた住所を右手の上に書け」 って脅迫電話がエンドレスリピートでかかってくるので、言われた通りに爆破して回ってる状況だからどうしても右手と左手でポインタが2つ必要なんですよ。 free(p); p = p->next; 「右手の上に書かれた住所に行って、そこを爆破せよ」 「右手の上に書かれた住所に行って、そこにある手紙に書かれた住所を右手の上に書け」 これだと既に手紙は爆破されてなくなっているので無理でしょうと。
退会済みユーザー

退会済みユーザー

2018/01/19 09:21

ありがとうございます。あとで検討します。とりあえずお礼まで。
退会済みユーザー

退会済みユーザー

2018/01/19 09:59

ありがとうございました。分かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問