
C言語基礎|配列の補足事項
ここまでで、配列の宣言・要素アクセス・初期化・走査・コピー・多次元配列まで一通り触れてきました。
でもC言語の配列には、「知っていると助かるけど、使いどころを間違えると危ない」補足トピックがいくつかあります。
この記事では、代表的な2つを紹介します。
- 可変長配列(VLA:variable length array)
- 要素指定子(designator:指示付き初期化)
どちらも便利に見える一方で、採用する前に知っておきたい落とし穴があります。ここを押さえると、配列の理解が一段深くなります。

可変長配列(VLA)って何?
ざっくり言うと
普通は配列の要素数は「定数」で決めますよね。
VLAは、要素数を 実行時に決まる値(変数) にできる配列です。
書式(宣言の形)
| 種類 | 書式 | 要素数が決まるタイミング |
|---|---|---|
| 通常の配列 | 型 変数名[定数式]; | コンパイル時 |
| VLA | 型 変数名[式]; | 実行時 |
例:関数引数 n に応じて配列サイズが決まる
void func(int n)
{
int a[n]; // VLA:実行時にnが決まってから確保される
}
VLAのメリットと注意点(ここ大事)
メリット
| メリット | うれしい場面 |
|---|---|
| 動的にサイズを変えられる | 入力された件数だけ一時的に配列を作りたい。 |
注意点(実務での落とし穴)
| 注意点 | 何が起きる? |
|---|---|
| 基本的にスタック確保 | サイズが大きいとスタックオーバーフローしやすい |
| コンパイラがサポートしない場合がある | 移植性が落ちる(STDC_NO_VLA が定義されることがある) |
| サイズチェックを怠ると危険 | n が負や巨大値だと未定義動作やクラッシュ要因になる |
| Cの方言差が出やすい | プロジェクトの方針によって禁止されがち |
「学習としては分かりやすい」けど、常用はおすすめしにくいタイプの機能です。
実務では、サイズが動くなら malloc を使って明示的に管理したり、固定最大長+実際の利用数だけ使う、みたいな設計が好まれます。
サンプルプログラム(入力件数ぶんだけ一時配列を作って合計する)
今回は「購入した商品数ぶんの価格を入力して合計を出す」にプログラムを例に解説をします。
プロジェクト名:chap5-10-1 ソースファイル名:chap5-10-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
// 入力された件数ぶんだけ一時配列を確保して合計を出す(VLAの例)
#include <stdio.h>
int main(void)
{
int n;
printf("商品はいくつ買いましたか:");
scanf("%d", &n);
if (n < 1 || n > 50) {
puts("入力できる個数は 1〜50 です。");
return 0;
}
int price[n]; // VLA:実行時に n 個の配列を確保
int sum = 0;
puts("価格を入力してください。");
for (int i = 0; i < n; i++) {
printf("%d個目の価格:", i + 1);
scanf("%d", &price[i]);
sum += price[i];
}
printf("合計金額は %d 円です。\n", sum);
return 0;
}解説
このコードの読みどころ
| 変数 | 役割 |
|---|---|
| n | 実際の要素数(実行時に決定) |
| price[n] | 入力された価格を保持する配列 |
| sum | 合計金額 |
- n を読み取った後に price[n] を宣言しているのがポイント
- つまり、n が決まる前に price[n] は作れません
- サイズが大きくなりすぎないように、n の範囲チェックを入れています。
要素指定子(designator)とは?
ざっくり言うと
初期化子で「この要素番号にこの値を入れる」と 添字つきで指定できる機能です。
書式(配列の designated initializer)
| 書式 | 意味 |
|---|---|
| 配列名 = { [添字] = 値, ... } | 指定した添字の要素に値を入れる |
例:
int a[] = { [2] = 5, 9, [6] = 3, 1 };
この意味は「次の順で初期化する」です。
- a[2] = 5
- 次の要素 a[3] = 9
- a[6] = 3
- 次の要素 a[7] = 1
指定されなかった要素は 0 で初期化されます。
要素指定子のメリット(使いどころが分かりやすい)
| 使いどころ | 何が嬉しい? |
|---|---|
| テーブルの一部だけ値を入れたい | 指定してない部分は0になるので書く量が減る。 |
| 定数テーブルや変換表 | “意味のある位置”にだけ値がある構造を作りやすい。 |
| 大きい配列の最後だけ初期化 | [999] = 1 のようにピンポイント指定ができる。 |
例:最後だけ 1、それ以外は 0
int a[1000] = { [999] = 1 };
サンプルプログラム(曜日ごとの営業時間テーブルを要素指定子で作る)
「穴のある初期化」が直感的に分かる題材です。
店の営業時間(分)を「開店日のみ設定」して、休業日は0のままにします。
プロジェクト名:chap5-10-2 ソースファイル名:chap5-10-2.c
// 要素指定子で「一部だけ」初期化した配列を使う例
#include <stdio.h>
int main(void)
{
// 0=Sun, 1=Mon, ... 6=Sat
// 開店日のみ営業時間(分)を設定、休業日は0のまま
int open_minutes[7] = {
[1] = 480, // Mon: 8 hours
[2] = 480, // Tue
[3] = 480, // Wed
[4] = 480, // Thu
[5] = 360, // Fri: 6 hours
// Sun(0), Sat(6) は指定なし → 0
};
puts("曜日ごとの営業時間(分)を表示します:");
for (int d = 0; d < 7; d++) {
if (open_minutes[d] == 0)
printf("Day %d: closed\n", d);
else
printf("Day %d: %d minutes\n", d, open_minutes[d]);
}
return 0;
}このコードの読みどころ
| 添字(d) | 曜日イメージ | open_minutes[d] | 意味 |
|---|---|---|---|
| 0 | Sun | 0 | closed |
| 1 | Mon | 480 | 8 hours |
| 2 | Tue | 480 | 8 hours |
| 3 | Wed | 480 | 8 hours |
| 4 | Thu | 480 | 8 hours |
| 5 | Fri | 360 | 6 hours |
| 6 | Sat | 0 | closed |
指定しなかった要素が 0 になるルールが、こういう用途と相性抜群です。
ここで覚えておきたい要点まとめ
| 項目 | 覚えること |
|---|---|
| VLA | 実行時にサイズが決まる配列。便利だが移植性・安全性に注意。大きなサイズは危険。 |
| 要素指定子 | 初期化で特定の添字に値を入れられる。穴あきテーブルに便利。指定しない要素は0。 |
