法大奥山研究室

 previous  contents

10.4. ポインタを含む和算


 ポインタを含む和算は,ポインタと整数型の間のみに許されます。ポインタ同士の和算は許されません。[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 のときのようにポインタ pstr に設定します。繰り返しの条件 *p != '\0' は「ナル文字でないならば」という意味になります。そして,繰り返す場合の条件変更 p++p1 増加させます。ポインタ p に整数 1 を加えること(ポインタと整数の和算)は許されます。(str左辺値ではないため,str++不可です。)

 ナル文字で繰り返し制御から抜けるので,メモリには次のように値が記憶されていることになります。(10.1 でのアドレスと異なるのは,アドレスは実行環境によって異なるため。)

+------------+------------+------------+------------+
| 0xbffffa98 | 0xbffffa99 | 0xbffffa9a | 0xbffffa9b | アドレス
+------------+------------+------------+------------+
|    'A'     |    'B'     |    'C'     |    'D'     | 値
+------------+------------+------------+------------+

+------------+------------+------------+------------+
| 0xbffffa9c | 0xbffffa9d | 0xbffffa9e | 0xbffffa9f | アドレス
+------------+------------+------------+------------+
|    'E'     |    'F'     |    'G'     |    '\0'    | 値
+------------+------------+------------+------------+

Q 文字列の末尾を探す方法
上の例では,
  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 を参照。


 previous  contents