プログラミング言語 C

配列とポインタには 注意すべき違いが 一つある。
ポインタは変数であり、したがって pa = a や pa++ は 意味のある演算となる。しかし 配列は変数ではない。
配列が関数に渡されるとき、(実際に) 渡されるのは 配列の先頭アドレスである。呼び出された関数内では、この引数は 局所的な変数として扱われる。
文字列の長さを求める関数 strlen を (ポインタ変数を使って) 書き換えてみる。

  1. /* strlen : 文字列 s の長さを返す */
  2. int strlen(char *s)
  3. {
  4. int n;
  5. for (n = 0; *s != '\0'; s++)
  6. n++;
  7. return n;
  8. }

s のインクリメントは、それが ポインタ変数なので 演算可能である。s++ は strlen を呼び出した関数内の文字列には影響しない。
strlen の仮引数は char[] と書くより
char *s
のほうがよいと思うが、それは このほうが 引数がポインタであることを 明示的に表しているからである。
配列の一部を その先頭のポインタを使って渡すことができる。array が配列だとして、
func(array + 2)
では、関数 func に array[2] の要素から始まる 配列のアドレスが渡される。
なお、この関数の宣言は、
func(int *a) { ....}
となる。
要素の存在が確実なら、配列を 逆方向にインデックスすることも可能である。
つまり a[-1], a[-2] は構文として正しく、a[0] の直前の要素を参照している。
当然だが、配列の限界内に存在しないオブジェクトは 参照してはいけない。(p121-122)


以前 でてきた 関数 get_line を ポインタ変数を使って 書いてみる。

  1. /* get_line */
  2. int get_line(char *s, int lim)
  3. {
  4. int i;
  5. for (i = 0; i < lim - 1 && (*s = getchar()) != EOF && *s != '\n'; ++s)
  6. ++i;
  7. if (*s == '\n')
  8. ++i;
  9. *s = '\0';
  10. return i;
  11. }

(これでいい . . . のかな ?)