動的な構造体配列

1 人ぶんが借りられるなら、n 人ぶんも借りられる

前回は malloc(sizeof(Student)) で構造体を 1 つ借りました。第 2 章で int を n 個借りたときと同じ理屈で、構造体も並べて借りられます。

Student *list = malloc(sizeof(Student) * n);

これで Student が n 個ぶん、すきまなく連続して並んだ領域が手に入ります。連続していることが効いてきて、list は先頭の Student を指すポインタなので、そのまま添字が使えます。

list[0].score = 80; list[1].score = 95;

list[i]*(list + i) の別の書き方です。list + i は「i バイト先」ではなく「Student i 個ぶん先」に進むので、構造体の大きさを自分で掛ける必要はありません。第 1 章のポインタ演算がそのまま構造体にも効いている、というだけの話です。

ドットか矢印かは、やはり左側で決まる

list[i] は実体なのでドット、list + i はポインタなので矢印です。どちらで書いても同じ場所を触ります。

list[i].score = 80; /* 左は実体 */ (list + i)->score = 80; /* 左はポインタ */

読みやすいほうを選んでかまいません。一覧を順に処理するときは添字のほうが素直なことが多いです。

free は 1 回でよい

n 人ぶんを 1 回の malloc で借りたなら、返すのも free(list) の 1 回だけです。malloc は借りた大きさを内部で覚えているので、こちらが n を伝える必要はありません。逆に free(&list[3]) のように途中の番地を渡してはいけません。free に渡してよいのは malloc が返したその番地だけです。

前回のように Student を 1 人ずつ別々に malloc していたら、話は変わります。そのときは人数ぶん free が必要です。「何回借りたか」と「何回返したか」を合わせる、という数え方で考えてください。

人数を先に読む形にする

入力の 1 行目に人数を置き、その数だけ確保してから読み込むと、何人でも同じコードで動きます。固定長配列のときのように #define MAX 100 を置いて、それを超えた入力を切り捨てる必要はもうありません。

int n; scanf("%d", &n); Student *list = malloc(sizeof(Student) * n);

なお n が 0 以下だと malloc に 0 や負の値を渡すことになります。実務では読み込んだ直後に範囲を確かめますが、今回の課題では 1 以上の値しか来ない前提で進めます。

要件

  1. 人数を読んでから malloc で人数分の Student を確保する
  2. 確保に失敗したら「確保できませんでした」と表示して return 1 する
  3. 全員を「名前 点数」の形で1行ずつ表示する
  4. 最後に「平均 」に続けて平均点を小数第1位まで表示する
  5. 確保した領域を free する

入出力例

main("3 佐藤 80 鈴木 95 田中 71") → "佐藤 80 鈴木 95 田中 71 平均 82.0" main("2 高橋 60 伊藤 91") → "高橋 60 伊藤 91 平均 75.5"

ヒント

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

メモ

動的な構造体配列

⌘S で保存