ポインタを含む和算は,ポインタと整数型の間のみに許されます。ポインタ同士の和算は許されません。[C99, 6.5.6, 2](c.f. 加算演算子)また,p
が配列の第i要素を指し示すポインタであるとすると,
p + n
は第 (i + n) 要素を指し示すポインタとなります。[C99, 6.5.6, 8]
/* Example 10.7 */ #include <stdio.h> int main(void) { char str[] = "ABCDEFG"; char *p; for(p = str; *p != '\0'; p++) printf("'%c' %x [%p]\n", *p, *p, p); return 0; }
これは,Example 10.5
において,ポインタの和算を利用して,配列 str[]
の各要素の値(ASCII文字と十六進法)とアドレスを出力させたものです。実行結果です。
'A' 41 [0xbffffa98] 'B' 42 [0xbffffa99] 'C' 43 [0xbffffa9a] 'D' 44 [0xbffffa9b] 'E' 45 [0xbffffa9c] 'F' 46 [0xbffffa9d] 'G' 47 [0xbffffa9e]
for
文における繰り返しの初期条件が p = str
ということで,Example 10.5
のときのようにポインタ p
を str
に設定します。繰り返しの条件 *p != '\0'
は「ナル文字でないならば」という意味になります。そして,繰り返す場合の条件変更 p++
は p
を 1
増加させます。ポインタ p
に整数 1
を加えること(ポインタと整数の和算)は許されます。(str
は左辺値ではないため,str++
は不可です。)
ナル文字で繰り返し制御から抜けるので,メモリには次のように値が記憶されていることになります。(10.1 でのアドレスと異なるのは,アドレスは実行環境によって異なるため。)
+------------+------------+------------+------------+ | 0xbffffa98 | 0xbffffa99 | 0xbffffa9a | 0xbffffa9b | アドレス +------------+------------+------------+------------+ | 'A' | 'B' | 'C' | 'D' | 値 +------------+------------+------------+------------+ +------------+------------+------------+------------+ | 0xbffffa9c | 0xbffffa9d | 0xbffffa9e | 0xbffffa9f | アドレス +------------+------------+------------+------------+ | 'E' | 'F' | 'G' | '\0' | 値 +------------+------------+------------+------------+
文字列の末尾を探す方法
上の例では,
for(p = str; *p != '\0'; p++) 文
によって文字列 ABCDEFG
の末尾の(ナル文字 '\0'
が入っている)アドレスまでポインタ p
が増加しました。すなわち,文字列の末尾を探した訳です。文字列の長さ無関係に文字列の末尾を探す方法は,このようにすればできる訳ですが,ただ単に文字列の末尾を探したいのであれば,論理演算と空文より次のようにすれば良いです。
for(p = str; *p; p++);
付言すると,str
が配列の第1要素を指し示すポインタであり,それが左辺値ではないという文法は,配列とポインタが異なる概念であることを意味している。C言語の先祖 B言語,そして B言語の先祖 BCPL ではポインタと配列は同じものであったが,C言語がそれら先祖から大きく飛躍したのは,型の導入と,そして配列とポインタの分離であった。詳しくは C言語の作者 Dennis M. Ritchie による C言語の歴史に関する著作 The Development of the C Language を参照。