コース一覧
    C言語中級 連結リスト・応用
    任意位置の挿入と削除

    C言語中級 連結リスト・応用

    C言語の連結リストと応用的なデータ操作を学び、実装でデータを扱うコースです。

    1
    連結リスト
    01. 配列の限界15分
    02. ノードを定義する15分
    03. 先頭に追加する15分
    04. リストを歩く15分
    05. 任意位置の挿入と削除15分
    06. リストを全解放する15分
    07. つくる リスト版成績管理15分
    08. 第5章クイズ10分
    2
    応用
    01. 動的な二次元配列15分
    02. コマンドライン引数15分
    03. バイナリ保存15分
    04. エラーの調べ方15分
    05. つくる 引数とバイナリ保存15分
    06. 第6章クイズ10分
    3
    総合制作
    01. リスト版を完成させる20分
    02. メモリバグ演習20分
    03. 自由拡張20分
    04. 完成と次のステップ10分

    任意位置の挿入と削除

    外したいノードの、前を知る必要がある

    いよいよ本題です。連結リストを選んだ理由は、途中の出し入れを詰め直しなしで済ませたいからでした。

    削除でやることは1つだけです。抜きたいノードの前にいるノードの矢印を、抜きたいノードの次へ付け替えます。

    c

    prev->next = target->next;

    これで並びから外れました。ほかのノードは1つも動いていません。配列なら後ろ全員を前へ詰めていたところが、代入1つになります。

    問題は prev の入手です。ノードは自分の次しか知らないので、前を指す矢印はどこにもありません。前を知る唯一の方法は、先頭から歩きながら「1つ前」を自分で覚えておくことです。

    c

    struct Node *prev = NULL;
    struct Node *p = head;
    while (p != NULL && strcmp(p->name, name) != 0) {
        prev = p;
        p = p->next;
    }

    ループを抜けたとき、p が見つかったノード、prev がその1つ前です。見つからなければ p は NULL になっています。

    先頭を消すときだけ形が違う

    prev が NULL のままループを抜けたなら、消したいのは先頭です。前がいないので付け替える矢印もなく、代わりに head 自身を進めます。

    c

    if (prev == NULL) {
        head = p->next;
    } else {
        prev->next = p->next;
    }
    free(p);

    この分岐を書き忘れると、先頭を消したときだけ NULL の中身に触れて落ちます。リストのコードで最初に踏むのはたいていここです。

    外してから解放する

    順番も大事です。free(p) を先にやってから p->next を読むと、返してしまった領域を読むことになります。運が良ければ正しい値が残っていて動いてしまうので、なおさら質が悪い間違いです。並びから外し、必要な値を読み終えてから解放する、と決めておきます。

    割り込ませるほうも矢印2本

    途中への挿入は、前になるノードが分かっていればさらに簡単です。

    c

    node->next = prev->next;
    prev->next = node;

    やはりこの順です。逆にすると prev の元の次を見失い、そこから後ろが全部つながらなくなります。「新しいノードの行き先を先に決めてから、自分を指してもらう」と覚えると、先頭追加のときと同じ話だと分かります。

    同じ名前が2人いたら

    今回の削除は、先頭から歩いて最初に一致したノードだけを外します。同じ名前が2人いた場合、残った1人は次に呼んだときに消えます。全部消したいのか1人だけなのかは仕様の話なので、どちらにするかを決めて、決めたほうに合わせて動くようにしておきます。曖昧なまま書くと、使う側から見て「消えたり消えなかったりする関数」になります。

    では、名前で削除する関数と、指定ノードの直後へ割り込ませる関数を書きましょう。

    要件

    1. 削除は先頭から歩きながら1つ前のノードを覚えておく
    2. 先頭を削除する場合と途中を削除する場合を分ける
    3. 並びから外したあとに free する
    4. insert_after は新しいノードの next を先に決めてから prev の next を書き替える
    5. prev が NULL のときは何もしない

    ヒント

    名前の比較は strcmp が 0 を返すかどうかで判定します

    ループを抜けたとき prev が NULL なら、消す相手は先頭です

    free したポインタの next は読めません。必要な値は解放前に読みます

    生田 陸人
    監修生田 陸人
    ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
    編集 ゆめさく編集部·公開 2026/08/07

    関連レッスン

    • リストを全解放する

      順序を守って最後まで解放できるようになります。

    • つくる リスト版成績管理

      配列版の成績管理をリスト版に移行できるようになります。

    • 第5章クイズ

      連結リストの操作とつなぎ替えの理解を確認します。

    • 動的な二次元配列

      ポインタのポインタで表形式のデータを確保できるようになります。

    このレッスンに出てくる用語

    意味があいまいなまま進んだ語は、ここから読み直せます。

    • 連結リスト各要素が次の要素へのポインタを持つ構造。
    • リスト順序付きで複数の値を扱うデータ構造
    • 配列サイズ固定の同型データの集まり
    • ループ繰り返し処理。矢印で戻すか専用記号で示す
    • 関数処理に名前を付けて再利用できる単位
    main.c
    エディタを読み込んでいます

    メモ

    任意位置の挿入と削除

    ⌘S で保存