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

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

ただいまの
回答率

90.49%

  • C

    3707questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 380

sanchu52

score 140

自己参照構造体を使ったリスト処理コードで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;
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

// pは一つのリストの先頭の要素のメモリー上の位置を表す
// 位置pから始まるリストを捨てる関数
void free_list(struct list *p)
{
    // p2は一つのリストの次の要素の位置のバックアップを表す
    struct list *p2;

    // 先頭の要素の位置pがNULLでない間、以下の処理を繰り返す
    while (p != NULL) {
        // 位置pにある要素から次の要素の位置をコピーしてp2に保存しておく
        // (先頭の要素が最後の要素の時は次の要素の位置としてNULLがコピーされる)
        p2 = p->next;
        // 位置pにある要素を捨てる
        free(p);
        // 先頭の要素の位置pへ取っておいた次の要素の位置p2をコピーする
        p = p2;
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 19:43

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

    キャンセル

  • 2018/01/18 19:51

    違います。

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

    キャンセル

  • 2018/01/18 20:00

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

    キャンセル

  • 2018/01/18 22:26

    そうじゃないです。free_listは必要です。
    例え話にすると右手p左手p2として

    p2 = p->next;
    free(p);
    p = p2;
    「右手の上に書かれた住所に行って、そこにある手紙に書かれた住所を左手の上に書け」
    「右手の上に書かれた住所に行って、そこを爆破せよ」
    「左手の上に書かれた住所を右手の上に書け」

    って脅迫電話がエンドレスリピートでかかってくるので、言われた通りに爆破して回ってる状況だからどうしても右手と左手でポインタが2つ必要なんですよ。

    free(p);
    p = p->next;
    「右手の上に書かれた住所に行って、そこを爆破せよ」
    「右手の上に書かれた住所に行って、そこにある手紙に書かれた住所を右手の上に書け」

    これだと既に手紙は爆破されてなくなっているので無理でしょうと。

    キャンセル

  • 2018/01/19 18:21

    ありがとうございます。あとで検討します。とりあえずお礼まで。

    キャンセル

  • 2018/01/19 18:59

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

    キャンセル

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

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    C言語 動的メモリ確保とリスト(構造体)を利用したプログラム

    現在このような結果で表示されるプログラムの作成を試みています。 >0p↲ >p >1d↲ >pd >0i↲ >ipd >2a↲ >ipad というように、格納位置

  • 解決済

    c言語 リスト構造の検索

    アドレス帳の検索機能だけのプログラムを作っています。 作りたいプログラムは、  1,検索したい人の名前を入力する  2,事前に登録された情報の中から部分一致検索する 

  • 解決済

    オーバーフローします...

    前提・実現したいこと アルファベット順に表示したいです どうやったらアルファベット順に表示できますか? もし,このままでいいならオーバーフローを直して欲しいです... アル

  • 解決済

    C言語のエラー修正について

    コード #include <stdio.h> #define New (element) RealNew( & element ) #define InputInt( number

  • 解決済

    線形リストでの単語の並べ替えがうまくいきません。

    前提・実現したいこと 単語の線形リストを作成し、同じ単語には1つのstruct word構造体を用い、単語の出現回数を数える。そして、出現単語を辞書順に並べ替える。 合っているかは

  • 解決済

    c言語 リスト構造について...

    前提・実現したいこと 最近C言語でリスト構造を勉強したので自己流でリスト構造のプログラムを作成したのですが正常に作動しません。どなたか解決法を教えてください。 説明不足だったの

  • 受付中

    リスト構造と待ち行列

    リスト構造と待ち行列をしたいのですが、よくわかりません。 おすすめのサイトや説明おねがいします。 #include <stdio.h> #include <stdlib.h>

  • 受付中

    C言語 リスト 新しいノードをリストの最後に追加

    C言語 リストについて ↓のプログラムでは入力した数字を逆順に表示 /* list.c */ #include <stdio.h> #include <stdlib.h> st

同じタグがついた質問を見る

  • C

    3707questions

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