p
が配列の第 i
要素を指し示すポインタのとき,
p + n
は第(i + n
)要素を指し示すポインタになるということは,間接演算子の文法から,配列の要素を意味する添字演算子 []
は,次の文法を持つこととなります。[C99, 6.5.1, 2]
x[i] == (*(x + i))
例えば,Example 10.8
の場合,メモリに記憶されている値とアドレス,そして,配列型 str
とその間接参照の関係は次のようになります。
+------------+------------+------------+------------+ | 0xbffffa98 | 0xbffffa99 | 0xbffffa9a | 0xbffffa9b | アドレス | str | str + 1 | str + 2 | str + 3 | →→ +------------+------------+------------+------------+ ↓ 間接参照 | 'A' | 'B' | 'C' | 'D' | 値 ↓ *(str + i) | str[0] | str[1] | str[2] | str[3] | ←← +------------+------------+------------+------------+ +------------+------------+------------+------------+ | 0xbffffa9c | 0xbffffa9d | 0xbffffa9e | 0xbffffa9f | アドレス | str + 4 | str + 5 | str + 6 | str + 7 | →→ +------------+------------+------------+------------+ ↓ 間接参照 | 'E' | 'F' | 'G' | '\0' | 値 ↓ *(str + i) | str[4] | str[5] | str[6] | str[7] | ←← +------------+------------+------------+------------+
したがって,Example 10.8
をポインタ p
を使わずに書き換えると,次のようになります。
/* Example 10.9 */ #include <stdio.h> int main(void) { char str[] = "ABCDEFG"; int i; for(i = 0; str[i] != '\0'; i++) printf("str[%d] '%c' %x [%p]\n", i, *(str + i), *(str + i), str + i); return 0; }
上の添字演算子の文法から,*(str + i)
は str[i]
とすることも可能です。
ポインタ p
を使わずとも,同じ目的が達成可能です。それでは,ポインタを利用する利点は何でしょうか。ポインタを利用せずに Example 10.9
のように要素番号を意味する i
を使った場合,i
を計算し,str
から i
番目のアドレスに移動し,そして,そのアドレスのメモリ箇所に記憶されている値を呼び出すことになります。というのは,配列は要素型のオブジェクトが連続してメモリに記憶されたデータだからです。最初からアドレスにアクセスできていれば,i
を計算し,str
から i
番目のアドレスに移動する必要はありません。一方,ポインタは最初からあるアドレスを指しています。ポインタの利点は,処理の高速化にあるのです。