array、&array[0]、&arrayの違い

添字指定の無い配列名を参照すると、「配列の先頭要素へのポインタ」として参照されますが、&演算子がついた配列名とは、どう違うのでしょうか。

[array.c]

      1 #include <stdio.h>
      2 
      3 int main(void)
      4 {
      5     int array[5];
      6 
      7     printf("%p -> %p\n", array, array+1);
      8     printf("%p -> %p\n", &array[0], &array[0]+1);
      9     printf("%p -> %p\n", &array, &array+1);
     10 
     11     return 0;
     12 }

[出力結果]

$ ./array
0xbf901b1c -> 0xbf901b20    # 4バイト差
0xbf901b1c -> 0xbf901b20    # 4バイト差
0xbf901b1c -> 0xbf901b30    # 20バイト差

array、&array[0]、&arrayとも、展開されるアドレスは一致しています。しかし、1インクリメントした先のアドレスは、それぞれ、4バイト先、4バイト先、20バイト先を示しています。

T型のポインタに対して+nした場合、(n * sizeof(T))バイト数分アドレスが進むため、それぞれの要素サイズ(sizeof(T))は、

array       # (要素サイズ = 4バイト)のオブジェクト
&array[0]   # (要素サイズ = 4バイト)のオブジェクト
&array      # (要素サイズ = 20バイト)のオブジェクト

と解釈されていることになります。

つまり、arrayと&arrayは、展開されるポインタ値は一致しているものの、

array  … 配列の0番目の要素(array[0])へのポインタ
&array … 配列全体(int array[])へのポインタ

という意味で解釈されていることが分かります。

まとめ。

「配列の先頭要素へのポインタ」と、「配列全体へのポインタ」は、同じアドレスを指していたとしても、配列要素の単位サイズは異なる。