ポインタと配列の違いとは

どこかで,“ポインタと配列の違いも分からない奴が”と嘆いているエントリを見て思い出したネタ.周りには,何度かネタとして話したこともありますが.

Cでは,“配列の宣言(定義?)”は存在しますが,それ以外の箇所では“配列”というものは存在せず,全てポインタとして扱われていたりします.Cでは,ポインタの示す値へアクセスする“*(p+1)”という記法に対する略記法(シンタックスシュガー)として,“p[1]”が定義されています.

そして,配列も宣言されると,必要な領域が確保された後にその領域への先頭アドレスを持つポインタ変数(x[n]の場合x,ただしxへの代入は不可)が生成され,その後はポインタ記法を用いて配列の各要素へアクセスすることになります.配列の変数名だけを書くと,その配列の先頭アドレスが得られるのもそのためだったりします.この辺りをベースに考えると,ポインタと配列が,何故そう振舞うのかがしっくり来るかと思います.

さて,ここからがネタ.上記の話を踏まえると次のようなコードが書けたりします.

#include 

int main(int argc, char* argv)
{
    int a = {0,2,4,6,8,10,12,16,18,20};
    
    printf("a[3] = %d\n", a[3]);
    printf("*(a + 3) = %d\n", *(a + 3));
    printf("*(3 + a) = %d\n", *(3 + a));
    printf("3[a] = %d\n", 3[a]);
    
    return 0;
}


実行結果
 a[3] = 6
 *(a + 3) = 6
 *(3 + a) = 6
 3[a] = 6

配列として宣言すると,配列用に確保された領域の先頭アドレスが格納されたaというポインタ変数が生成される.a[3]は,*(a + 3)の略記法なので,もちろん後者の記法でも参照できる.aと3は反対に書いても同じなので,*(3 + a)もOK.すると,その略記法である3[a]でも参照することができる,という訳です.

だから何だって話ですが,ネタとして話すには面白いかも.

で,結局ポインタと配列の違いって何だろう?と思ってGoogle先生に聞いてみる.

void f()
{
    char *a = "ABC";
    char b[] = "DEF";
    
    *a = '1';   /* NG */
    b[0] = '1'; /* OK */
}

コメントでも示していますが,ポインタで定義したほうはNGになる場合があります(ならない場合もあるので,やっかいなんですが)。


C MAGAZINE - プログラミングの禁じてWeb版C言語編:ポインタと配列を混同している

なるほど.