🗃️ 配列
🎯 配列の初期化の書き方を使い分けられ、未初期化の危険を避けられる
宣言しただけの配列の中身は不定です。前に別の処理が使っていた値がそのまま残っている、いわばゴミの状態。読んでも意味のない数字が出てきます。だから配列は、作ると同時に中身を決めるのが基本です。
#include <stdio.h>
int main(void)
{
int a[5] = {60, 85, 40, 90, 75}; // 5個ぶんを並べて初期化
for (int i = 0; i < 5; i++) {
printf("%d ", a[i]);
}
printf("\n");
return 0;
}足りないぶんは0で埋まる
初期化子が要素数より少ないとき、残りは自動的に 0 になります。この性質を使った定番の書き方が {0} です。
int a[5] = {1, 2}; // → 1, 2, 0, 0, 0
int b[5] = {0}; // → 全部 0
int c[100] = {0}; // 100個ぜんぶ 0
int d[100] = {}; // C23。より意図がはっきりする書き方逆に、要素数より多く書くとコンパイルエラーです。これは親切なエラーなので、ありがたく受け取りましょう。
なぜ初期化にこだわるのか
未初期化の配列を読むのは、境界外アクセスと同じ「未定義動作」です。手元では 0 が並んでいるように見えても、それは前の処理がたまたま0を残していただけかもしれません。実行するタイミングや環境が変われば、まったく違う数字が現れます。「合計を出すたびに答えが違う」という不気味なバグの正体は、たいていこれです。
個数を書かない書き方
初期化子を並べるなら、個数は省略できます。コンパイラが数えてくれます。
int a[] = {3, 1, 4, 1, 5}; // 要素数5の配列になる
int n = sizeof(a) / sizeof(a[0]); // 5要素を1つ増やしたときに個数を直し忘れる、という事故がなくなるので、値が決まっている表にはこの書き方が便利です。曜日の名前や月ごとの日数のように「あとから項目が増えるかもしれない表」では、とくに効果があります。ただし個数を省略できるのは初期化子を書いたときだけで、int a[]; とだけ書くことはできません。
位置を指定して初期化する
C99以降では、添字を指定して飛び飛びに初期化できます。指定しなかった要素は0のままです。また、宣言のあとで「もう一度すべて0に戻したい」ときは、初期化子は使えないのでループで書きます。
int score[10] = { [0] = 100, [9] = 50 }; // 他はすべて0
// 途中でもう一度すべて0に戻すときはループで
for (int i = 0; i < 10; i++) {
score[i] = 0;
}罠・注意
int a[5];)は中身が不定です。「たまたま0だった」に頼ると、環境が変わった瞬間に壊れます。a = {1, 2, 3}; と書くことはできません。配列そのものへの代入はCでは許されておらず、値を入れ直したいならループで1つずつ入れます。同じ理由で b = a; という配列まるごとのコピーもできません。これもループで1要素ずつ写します。{0} は「全部0」になりますが、{1} は「先頭だけ1で残りは0」です。「全部1」にはなりません。全要素を同じ値にしたいならループを使います。int a[5] = {1, , 3}; のように途中を空けることはできません。飛ばしたいときは、上で見た添字指定の書き方を使います。= {0} を付けておく。ゴミの値で悩む時間がまるごと消えるよまとめ: 配列は宣言と同時に初期化する。足りないぶんは0埋め、{0} で全ゼロ、個数省略も可能。後からのまとめ代入はできません。
もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。