先頭に追加する

先頭は、動かすものが無い場所

前回はノードを手で2つ作ってつなぎました。今回はそれを関数にして、何人でも足せるようにします。足す場所は先頭にします。

先頭を選ぶのは手抜きではありません。配列で先頭に入れるのが一番重かったのを思い出してください。リストでは逆に、先頭がいちばん軽い場所です。前のノードを探す必要がなく、動かす要素も無く、書き替えるのは矢印2本だけだからです。

空のリストは NULL

リスト全体は、先頭のノードを指すポインタ1本で表します。この変数をふつう head と呼びます。

1人もいない状態は head == NULL です。空のリストのために特別な入れ物を用意しないところが大事で、おかげで「1人もいないとき」と「1人以上いるとき」を同じコードで扱えます。

つなぐ順番を間違えない

追加は次の2行です。

node->next = head; head = node;

必ずこの順です。先に head = node; としてしまうと、元の先頭を指していた値がどこにも残らず、そのあと node->next = head; と書けば自分自身を指してしまいます。こうなると2人目以降が丸ごと迷子になり、しかもリストを歩くと永久に終わりません。

head を書き替えるので、戻り値で返す

追加を関数にすると、先頭が変わるという点が引っかかります。

struct Node *insert_head(struct Node *head, const char *name, int score);

head を引数で受け取っても、それは呼び出し元の変数の写しなので、関数の中で入れ替えても呼び出し元には伝わりません。入門でポインタ渡しを見たときと同じ話です。

やり方は2つあります。新しい先頭を戻り値で返して呼び出し元で受け直す形と、struct Node ** を受け取って呼び出し元の変数そのものを書き替える形です。この章では読みやすい前者で通します。呼び出し側はこうなります。

head = insert_head(head, "田中", 82);

代入を忘れると追加が消えるので、そこだけ気をつけます。

確保に失敗したとき

mallocNULL を返したら、ノードは作れていません。そのときは元の head をそのまま返して、リストを壊さずに諦めます。

名前は箱ごとコピーする

ノードの namechar[32] の配列です。受け取った const char *name をそのまま node->name = name; とは書けませんし、書けたとしてもやりたいこととは違います。呼び出し元の文字列を指すだけになるので、その文字列が次の読み込みで上書きされた瞬間、リストの中の名前まで変わってしまうからです。

strncpy(node->name, name, 31); node->name[31] = '�';

strncpy は上限を超えると終端の 0 を置いてくれないので、最後の1文字を自分で入れておきます。ノードは自分の名前を自分の中に持つ、という形にしておけば、元の文字列がどうなろうとリストは無事です。

では、3人を順に先頭追加してみましょう。読み込んだ順と表示される順が逆になるはずです。

要件

  1. malloc でノード1個分を確保する
  2. 確保に失敗したら元の head をそのまま返す
  3. name は文字列としてコピーし、score は代入で入れる
  4. 新しいノードの next を元の先頭に向けてから、そのノードを返す

入出力例

main("田中 82", "鈴木 91", "佐藤 70") → "佐藤 70鈴木 91田中 82点" main("中村 55", "山本 100", "高橋 64") → "高橋 64山本 100中村 55点"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.c
学習モード

メモ

先頭に追加する

⌘S で保存