先頭に追加する
先頭は、動かすものが無い場所
前回はノードを手で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);代入を忘れると追加が消えるので、そこだけ気をつけます。
確保に失敗したとき
malloc が NULL を返したら、ノードは作れていません。そのときは元の head をそのまま返して、リストを壊さずに諦めます。
名前は箱ごとコピーする
ノードの name は char[32] の配列です。受け取った const char *name をそのまま node->name = name; とは書けませんし、書けたとしてもやりたいこととは違います。呼び出し元の文字列を指すだけになるので、その文字列が次の読み込みで上書きされた瞬間、リストの中の名前まで変わってしまうからです。
strncpy(node->name, name, 31);
node->name[31] = '�';strncpy は上限を超えると終端の 0 を置いてくれないので、最後の1文字を自分で入れておきます。ノードは自分の名前を自分の中に持つ、という形にしておけば、元の文字列がどうなろうとリストは無事です。
では、3人を順に先頭追加してみましょう。読み込んだ順と表示される順が逆になるはずです。
要件
- malloc でノード1個分を確保する
- 確保に失敗したら元の head をそのまま返す
- name は文字列としてコピーし、score は代入で入れる
- 新しいノードの next を元の先頭に向けてから、そのノードを返す
入出力例
main("田中 82", "鈴木 91", "佐藤 70") → "佐藤 70点
鈴木 91点
田中 82点"
main("中村 55", "山本 100", "高橋 64") → "高橋 64点
山本 100点
中村 55点"