C言語 | ポインタ | ポインタ演算

ポインタ演算を使うと、ポインタが参照する対象を変更できます。特に配列の要素を順番に参照するときに便利です。

アドレスを計算する

ポインタはメモリアドレスを保持し、データ型を持ちます。演算が意味を持つのは、配列のような連続した有効なメモリ領域の範囲内です。無関係なアドレスを間接参照すると、クラッシュや未定義動作の原因になります。

コード1

#include <stdio.h>

int main() {
  char chStr[] = "Kitty on your lap";
  int iCount;

  for (iCount = 0; chStr[iCount]; ++iCount)
    printf("&chStr[%d] = %p\n", iCount, (void *)&chStr[iCount]);
  return 0;
}

配列は連続したメモリ領域を使うため、各要素のアドレスは順番に増加します。char は1バイトなので、chStr[0] のアドレスに5を加えると chStr[5] のアドレスになります。

コード2

#include <stdio.h>

int main() {
  int iArray[] = { 10, 100, 1000 };
  int *iPo = &iArray[0] + 1;

  printf("*iPo = %d\n", *iPo);
  return 0;
}

ここで iPoiArray[1] を指します。ポインタ演算は常に1バイト単位ではなく、参照先の型を単位として進みます。

コード3

#include <stdio.h>

int main() {
  int iArray[] = { 2, 4 };

  printf("&iArray[0] = %p\n", (void *)&iArray[0]);
  printf("&iArray[1] = %p\n", (void *)&iArray[1]);
  return 0;
}

int が4バイトの環境では、表示される2つのアドレスの差は4バイトです。この調整はコンパイラが自動的に行います。

コード4

#include <stdio.h>

int main() {
  int iArray[] = { 2, 4 };
  int *iPo = &iArray[0];

  printf("*iPo = %d : iPo = %p\n", *iPo, (void *)iPo);
  iPo += 1;
  printf("*iPo = %d : iPo = %p\n", *iPo, (void *)iPo);
  return 0;
}

iPo += 1 の後、iPo は2番目の要素を指します。int * に1を加えると、アドレスは sizeof(int) バイト進みます。