配列とポインタの違いとは?C言語で混乱しやすい関係をわかりやすく解説

目次

C言語文法解説シリーズ

本記事は「C言語文法解説シリーズ」の1つです。
C言語の文法を、組み込み開発の視点も交えて解説します。

👉 C言語文法解説シリーズ一覧はこちら

C言語では「配列とポインタは同じ」と言われることがあります。
しかし、配列とポインタは別物です。

確かに似た動きをしますが、違いを理解していないとバグの原因になります。

この記事では

  • 配列とポインタの違い
  • なぜ同じように見えるのか
  • 実務で重要なポイント

を分かりやすく解説します。

基本的なポインタの使い方についてはこちらの記事で解説しています。


配列とポインタは同じではない

まずはよく見るコードです。

C
int arr[3] = {1, 2, 3};
int *p = arr;

このコードでは

  • arr → 配列
  • p → ポインタ

pには配列の先頭アドレスが入ります。

つまり

C
arr:
[1][2][3]

p:

[1][2][3]

このため同じように使えます。

C
printf("%d", arr[0]);
printf("%d", p[0]);

どちらも 1 になります。

初心者さん

同じように使えるなら同じでは?

エンジニアくん

配列はデータそのものなんだ

エンジニアくん

ポインタは場所を指してるだけ

初心者さん

なるほど、だから似てるだけなんですね


違い① sizeof の結果が違う

一番分かりやすい違いはこれです。

C
int arr[3];
int *p;

sizeof(arr);
sizeof(p);

結果はこうなります。

C
sizeof(arr) → 12
sizeof(p)   → 8

まず配列から見てみます。

C
int arr[3];

これは intが3つ並んだ配列 です。

int は通常 4 バイトなので

C
[ int ][ int ][ int ]
  4      4      4

合計は

4 + 4 + 4 = 12 バイト

つまり

C
sizeof(arr) = 12

になります。


ではポインタはどうでしょうか。

C
int *p;

これは

「intを入れる変数」ではなく
intがある場所を指す変数 です。

例えば

C
int a = 10;
int *p = &a;

このときメモリのイメージはこうなります。

C
a: 10
アドレス 1000

p: 1000

つまり

  • a は値を持つ
  • p は「場所(アドレス)」を持つ

という違いがあります。


ではこの「アドレス」は何バイトでしょうか?

アドレスはメモリ上の場所を表す番号です。

例えば

C
0x00007FF8A1234567

このような値になります。

この値を丸ごと保存する必要があるため、
ポインタは 8バイト になります。

つまり

C
sizeof(p) = 8

になります。


まとめると

配列

C
[データ][データ][データ]

ポインタ

C
[アドレス]

配列はデータそのものを持ち
ポインタは場所を持つ

この違いによって

C
sizeof(arr) → 12
sizeof(p)   → 8

という差が生まれます。

メモリの視点での配列とポインタの違いはこちらの記事で解説しています。


違い② 配列は代入できない

ポインタは代入できます。

C
int *p;
int a = 10;

p = &a;

しかし配列は代入できません。

C
int arr[3];
int b[3];

arr = b;   // エラー

配列は固定されたメモリだからです。

一方ポインタは指す先を変更できます。

C
int a = 10;
int b = 20;

int *p;
p = &a;
p = &b;
初心者さん

配列は動かせないんですね

エンジニアくん

ポインタは行き先を変えられる

初心者さん

だから別物なんですね


配列はポインタに変換される

ここが混乱の原因です。

配列は式の中で使うと、先頭アドレスに変換されます。

C
int arr[3];

int *p = arr;

これは実際には

C
int *p = &arr[0];

と同じです。

つまり

配列はポインタに変換される

だから同じように使えるのです。


関数引数ではポインタになる

関数の引数に配列を書くと

C
void func(int arr[])

これは実際には

C
void func(int *arr)

と同じです。

つまり関数の中では
配列ではなくポインタとして扱われます。

C
void func(int arr[])
{
    sizeof(arr);
}

この場合

配列サイズではなく
ポインタサイズになります。

ここは非常にバグになりやすいポイントです。


まとめ

配列とポインタの違い

  • 配列はデータ本体
  • ポインタはアドレス
  • sizeof の結果が違う
  • 配列は代入できない
  • 配列は式の中でポインタに変換される
  • 関数引数ではポインタになる

配列とポインタは似ていますが
本質的には別物です。

この記事が参考になった方へ

C言語の基本文法を一覧で整理しています。

👉 C言語文法解説シリーズ一覧はこちら

技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。

小さなご相談からでもお気軽にご連絡ください。

お問い合わせはこちら

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする


目次