初心者さん配列って、ただの変数が並んだものですよね?



新人さんはそう思いがちだけど、実はそこにかなり重要な仕組みがあるんだ。
配列はC言語の中でも、
👉 メモリの理解に直結する超重要な概念
ここをしっかり理解しておくと、
ポインタ・文字列・構造体といった後の理解が一気に楽になります。
この記事では、配列の基本だけでなく、
👉 メモリ上でどう扱われているのか
まで含めて丁寧に解説します。
C言語文法解説シリーズ
本記事は「C言語文法解説シリーズ」の1つです。
C言語の文法を、組み込み開発の視点も交えて解説しています。
C言語文法解説シリーズ一覧はこちら





配列って、ただの変数の集まりですよね?



それも正しいけど、**本質は“メモリの並び”**なんだよ
配列とは
C言語の配列とは、
👉 同じ型のデータを連続して格納する仕組みです。
例えば:
int arr[3] = {10, 20, 30};このように書くと、
3つのint型の値をまとめて扱うことができます。
配列の一番重要なポイント
ここが最重要👇
👉 配列は連続したメモリ領域に配置される
メモリ上のイメージ
配列は、メモリ上ではこのように並びます。
アドレス 値
0x1000 10
0x1004 20
0x1008 30👉 同じサイズで順番に並ぶ
int型なら通常4バイトなので、
4バイトずつずれて配置されます。
配列とメモリ配置の関係についてはこちらの記事で詳しく解説しています。


インデックスとは
配列の要素には「番号」でアクセスできます。
arr[0]; // 10
arr[1]; // 20
arr[2]; // 30👉 この番号を「インデックス」と呼びます
ポイント👇
- 0から始まる
arr[n]は「n番目の要素」
📌 なぜインデックスは0から始まるのか
配列のインデックスが0から始まる理由は、
👉 メモリ上のアドレス計算の仕組みにあります。
まず、配列はメモリ上に連続して配置されます。
int arr[3] = {10, 20, 30};このときのメモリは、次のようになります。
アドレス 値
0x1000 10 ← arr[0]
0x1004 20 ← arr[1]
0x1008 30 ← arr[2](※ intは4バイトとする)
📌 配列アクセスの正体
C言語では、配列アクセスは次のように解釈されます。
arr[n]これは内部的に、
*(arr + n)と同じ意味です。
📌 何をしているのか
この式は、次の2ステップで処理されています。
① arr + n
👉 先頭アドレスから「n個分」進む
② *(...)
👉 その場所の値を取り出す
📌 実際の動き
例えば arr[1] の場合:
arr[1] == *(arr + 1)これを分解すると👇
arr = 0x1000(先頭アドレス)
arr + 1 = 0x1004(4バイト進む)
*(arr+1) = 20📌 なぜ0から始まるのか
ここが本質👇
arr[0] == *(arr + 0)つまり、
arr + 0 = 先頭アドレスそのまま👉 何も足さない位置が最初の要素
だから、
- 0番目 → 先頭
- 1番目 → 1つ先
- 2番目 → 2つ先
というルールになります。
📌 もし1から始めたら?
仮に配列が1から始まるとすると、
arr[1] = 先頭
arr[2] = 1つ先というズレた設計になります。
すると毎回
👉 「-1補正」が必要になる
*(arr + (n - 1))👉 無駄な計算が増える
まとめ
- 配列アクセスは
*(arr + n)と同じ arrは先頭アドレス+ nで要素分だけ進む+0が最初の要素になる
👉 だからインデックスは0から始まる
配列名は先頭要素のアドレスとして扱われる
C言語では、配列名は多くの場面で
配列の先頭要素のアドレス
として扱われます。
例えば、次の配列を考えます。
int arr[3] = {10, 20, 30};このとき、arr は配列全体を表す名前ですが、式の中では多くの場合、先頭要素である arr[0] のアドレスとして扱われます。
arrは、多くの場面で次と同じような意味になります。
&arr[0]例えば、次のように書けます。
int *p = arr;これは、次のように書いているのとほぼ同じです。
int *p = &arr[0];つまり、ポインタ p は配列の先頭要素を指します。
arr[0] → 10
arr[1] → 20
arr[2] → 30
p ──→ arr[0]この状態で、次のように書くと arr[0] の値を取得できます。
printf("%d\n", *p); // 10さらに、ポインタに1を足すと、次の要素を指します。
printf("%d\n", *(p + 1)); // 20
printf("%d\n", *(p + 2)); // 30これは、次の配列アクセスと同じ意味です。
printf("%d\n", arr[1]); // 20
printf("%d\n", arr[2]); // 30つまり、C言語では次のような関係があります。
arr[i] == *(arr + i)この仕組みがあるため、配列とポインタは非常に深い関係があります。
ただし、ここで注意したいのは、
配列そのものとポインタは同じものではない
という点です。
配列名は「先頭要素のアドレスとして扱われる場面が多い」だけで、配列そのものがポインタ変数になるわけではありません。
この違いは、後の記事で扱う
「char配列とポインタの違い」や
「sizeofとstrlenの違い」で非常に重要になります。
配列とポインタの関係についてはこちらの記事で詳しく解説しています。


配列とループ処理
配列は、for文などのループ処理と非常に相性が良いです。
その理由は、配列の要素が
arr[0]
arr[1]
arr[2]のように、連続した番号で管理されているからです。
例えば、次の配列があるとします。
int arr[3] = {10, 20, 30};この配列の要素を1つずつ表示する場合、次のように書けます。
for (int i = 0; i < 3; i++) {
printf("%d\n", arr[i]);
}このコードでは、i の値が次のように変化します。
i = 0 → arr[0] → 10
i = 1 → arr[1] → 20
i = 2 → arr[2] → 30つまり、i をインデックスとして使うことで、
配列の要素を順番に処理できるわけです。
ここで重要なのは、条件式が i < 3 になっている点です。
配列 arr[3] の要素数は3つですが、使えるインデックスは次の3つだけです。
arr[0]
arr[1]
arr[2]arr[3] は存在しません。
そのため、次のように書くと危険です。
for (int i = 0; i <= 3; i++) {
printf("%d\n", arr[i]);
}この場合、i が3のときに arr[3] へアクセスしてしまいます。
C言語では、配列の範囲外アクセスを自動で止めてくれません。
そのため、コンパイルできても、実行時に不正な値を読んだり、プログラムが異常終了したりする可能性があります。
配列をループで扱うときは、
「要素数」と「最後のインデックス」は違う
という点を必ず意識する必要があります。
要素数3 → 最後のインデックスは2
要素数5 → 最後のインデックスは4
要素数10 → 最後のインデックスは9
C言語のループ処理(for, while)についてはこちらの記事でまとめています。




またループ処理は多次元配列と組み合わせて使われることが特に多いです。
多次元配列についてはこちらの記事で解説しています。


配列のサイズ(注意点)
int arr[3];この場合
👉 要素数は3
👉 インデックスは 0〜2
ここでよくあるミス👇
arr[3]; // NG(範囲外アクセス)👉 C言語は範囲チェックをしてくれない
→ バグの原因になります
実務で重要なポイント
配列は便利ですが、注意点もあります。
■ サイズは固定
int arr[3];👉 後からサイズ変更できない
■ 範囲外アクセスは危険
👉 クラッシュや不具合の原因になる
■ メモリを直接扱う意識が必要
👉 C言語は安全に守ってくれない
まとめ
- 配列は同じ型のデータをまとめる仕組み
- メモリ上では連続して配置される
- インデックスでアクセスする(0始まり)
- 配列名は先頭アドレスとして扱われる
👉 配列は“メモリ構造の入口”になる重要な概念
この記事が参考になった方へ
配列を含むC言語の基本文法をこちらの記事で整理しています。


組み込みエンジニアとして技術を学ぶことは重要ですが、
キャリアや副業についても同時に考える必要があります。
副業の現実や市場価値、今後のキャリア戦略については、
こちらの記事でまとめています。


技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。
小さなご相談からでもお気軽にご連絡ください。









コメント