Pointer Arithmetics
以前、ポインタとは何か、そしてポインタの操作方法を学びました。このチュートリアルでは、ポインタに対する算術演算について学習します。 C言語のポインタには、++、--、-、+ といった複数の算術演算を適用できます。
(++) によるポインタのインクリメント
他の変数と同様に、++ 演算はその変数の値を増加させます。今回の場合、変数はポインタなので、その値を増加させると、ポインタが指すメモリ内のアドレスが増加します。 この演算を例に、配列と組み合わせてみましょう:
#include <stdio.h>
int main()
{
int intarray[5] = {10,20,30,40,50};
int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] has value %d - and address @ %x\n", i, intarray[i], &intarray[i]);
int *intpointer = &intarray[3]; // 配列の4番目の要素を指す
printf("address: %x - has value %d\n", intpointer, *intpointer); // 4番目の要素のアドレスを出力する
intpointer++; // ポインタのアドレスを増やして配列の5番目の要素を指すようにします。
printf("address: %x - has value %d\n", intpointer, *intpointer); // 5番目の要素のアドレスを出力する
return 0;
}
(--) によるポインタの減少
前の例で ++ 演算子を使用してポインターの指すアドレスを 1 つ増やしたのと同様に、デクリメント演算子 (--) を使用して、指すアドレスを 1 つ減らすことができます。
#include <stdio.h>
int main()
{
int intarray[5] = {10,20,30,40,50};
int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] has value %d - and address @ %x\n", i, intarray[i], &intarray[i]);
int *intpointer = &intarray[4]; // 配列の5番目の要素を指す
printf("address: %x - has value %d\n", intpointer, *intpointer); // 5番目の要素のアドレスを出力する
intpointer--; // ポイントのアドレスを減らして、配列の4番目の要素を指すようにする
printf("address: %x - has value %d\n", intpointer, *intpointer); // 4番目の要素のアドレスを出力する
return 0;
}
(+) でポインタを追加する
先ほど、ポインタの指すアドレスを1ずつ増やしました。次のように整数値で増やすこともできます。
#include <stdio.h>
int main()
{
int intarray[5] = {10,20,30,40,50};
int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] has value: %d - and address @ %x\n", i, intarray[i], &intarray[i]);
int *intpointer = &intarray[1]; // 配列の2番目の要素を指す
printf("address: %x - has value %d\n", intpointer, *intpointer); // 2番目の要素のアドレスを出力する
intpointer += 2; // ポイントのアドレスを2つシフトして、配列の4番目の要素を指すようにします。
printf("address: %x - has value %d\n", intpointer, *intpointer); // 4番目の要素のアドレスを出力する
return 0;
}
出力では、メモリ内でアドレスが8ステップシフトしていることに注目してください。なぜだろうと疑問に思うかもしれません。 答えは簡単です。ポインタがint型ポインタであり、int型変数のサイズが4バイトであるため、メモリは4ブロックシフト可能です。 コードでは、最初のアドレスに2(+2)シフトしたので、2 x 4バイト = 8になります。
(-) によるポインタの減算
同様に引き算もできます:
#include <stdio.h>
int main()
{
int intarray[5] = {10,20,30,40,50};
int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] has value: %d - and address @ %x\n", i, intarray[i], &intarray[i]);
int *intpointer = &intarray[4]; // 配列の5番目の要素を指す
printf("address: %x - has value %d\n", intpointer, *intpointer); // 5番目の要素のアドレスを出力する
intpointer -= 2; // ポイントのアドレスを2つシフトして、配列の3番目の要素を指すようにする
printf("address: %x - has value %d\n", intpointer, *intpointer); // 3番目の要素のアドレスを出力する
return 0;
}
ここでも、アドレスは 4 バイトのブロック単位でシフトされます (int の場合)。
その他の操作
他にも比較演算(>、<、==など)があります。考え方は変数の比較と非常に似ていますが、この場合はメモリアドレスを比較します。
Exercise
intarray の最後の 3 つのアドレスを、int へのポインターの配列である parray にコピーします。