トラック8・🗃️配列

配列の初期化いろいろ

読む目安 約11分・ゴール:配列の初期化の書き方を使い分けられ、未初期化の危険を避けられる

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

宣言しただけの配列の中身は不定です。前に別の処理が使っていた値がそのまま残っている、いわばゴミの状態。読んでも意味のない数字が出てきます。だから配列は、作ると同時に中身を決めるのが基本です。

#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;
}

罠・注意

ビット迷ったら = {0} を付けておく。ゴミの値で悩む時間がまるごと消えるよ

まとめ: 配列は宣言と同時に初期化する。足りないぶんは0埋め、{0} で全ゼロ、個数省略も可能。後からのまとめ代入はできません。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

次のプログラムの出力はどれですか。

#include <stdio.h>

int main(void)
{
    int a[5] = {7, 8};

    for (int i = 0; i < 5; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}
  1. 7 8 7 8 7
  2. 7 8 0 0 0
  3. 7 8 と表示され残りは不定の値
  4. コンパイルエラー
答えを見る

正解:B(7 8 0 0 0)

初期化子が要素数より少ないとき、残りの要素は自動的に 0 になります。この性質を利用したのが int a[100] = {0}; という全ゼロ初期化の定石です。

確認問題 2

配列の初期化について、誤っているものはどれですか。

  1. int a[] = {3, 1, 4}; と書くと要素数3の配列になる
  2. int a[3] = {1}; は全要素が1になる
  3. 初期化を書かない配列の中身は不定である
  4. 宣言のあとで a = {1, 2, 3}; とまとめて代入することはできない
答えを見る

正解:B(int a[3] = {1}; は全要素が1になる)

{1} は「先頭だけ1、残りは0」です。全要素を同じ値にしたいならループで入れます。{0} が全ゼロになるのは、たまたま埋められる値が0だからです。

「配列」の目次

  1. 配列とは——箱の行列
  2. 添字と0始まりの理由
  3. 配列とループの黄金コンビ
  4. 境界外アクセスという重大事故
  5. 配列の初期化いろいろ
  6. 多次元配列
  7. 配列を関数に渡す——入口編
  8. 集計・最大値・検索の定石

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版