配列
変数を5つ用意するのはつらい
前章までは、点数を持つのに int kokugo, sugaku, eigo; のように変数を1つずつ用意していました。3科目ならまだ書けますが、5科目なら5個、40人ぶんなら40個の名前を考えることになります。しかも変数名は固定なので、「3番目の点数」を番号で選ぶことができません。ループと相性が最悪なのです。
これを解決するのが 配列 です。同じ型の値を、番号の付いた箱として1つの名前でまとめて持てます。
int scores[5];int が中身の型、scores が名前、[5] が箱の個数です。これで int が5個ぶん、メモリ上に連続して確保されます。個数のところには変数ではなく、5 や #define した定数のような、コンパイル時に決まる値を書くのが基本です。
添字は0から始まる
1つ1つの箱は 添字 (そえじ) を付けて取り出します。
scores[0] = 80; // 1科目目
scores[1] = 65; // 2科目目
printf("%d\n", scores[0]);ここが最初の関門で、添字は1ではなく 0から始まります。int scores[5] の有効な添字は 0 から 4 までで、scores[5] は存在しません。「1科目目が scores[0]」という1つずれた対応を、指が覚えるまで意識して書いてください。
0から始まるのは、配列の先頭からいくつ後ろにずれた箱かを表しているからです。先頭の箱は「0個ぶんずれた箱」なので0番になります。
宣言と同時に値を入れる
1つずつ代入するかわりに、宣言と同時に並べて書けます。
int scores[5] = {80, 65, 92, 74, 58};
int counts[5] = {0}; // 残りも自動で0になる
int days[] = {31, 28, 31}; // 個数を書かないと、並べた数だけ確保される{0} と書くと、明示していない残りの要素は 0 で埋められます。全部を 0 で始めたいときの定番です。逆に int scores[5]; とだけ書いた場合、中身は何が入っているか分かりません。読む前に必ず値を入れてください。
範囲外は誰も止めてくれない
C には、添字が範囲内かを実行時に確かめるしくみがありません。scores[5] や scores[-1] と書いてもコンパイルは通り、実行しても何も言われないことがあります。実際には配列の外側にある別の変数の場所を読み書きしてしまい、まったく関係ない変数の値が壊れます。
原因の行と、おかしくなる場所が離れるので、追いかけるのが非常に大変です。配列を触るときは「上限は個数マイナス1」を毎回確かめる、という習慣で防ぎます。
では、5科目の点数を配列で持ってみましょう。
要件
- int の配列 scores に 80, 65, 92, 74, 58 を入れる
- 1科目目は80点です の形で3行表示する
- 表示する科目は1科目目・3科目目・5科目目の3つ
入出力例
main("") → "1科目目は80点です
3科目目は92点です
5科目目は58点です"