C++ポインタ(3)-算術演算

2886 ワード

ポインタは整数を加算または減算できます.ポインタのこのような演算の意味は、通常の数値の加減演算の意味とは異なり、バイト単位である.
char a[20];
int *ptr=(int *)a;//           a   
ptr++;

上記の例では、ポインタptrのタイプはint*であり、その指向タイプはintであり、整数変数aを指すように初期化される.次の3文では、ポインタptrに1が加算され、コンパイラは、ポインタptrの値にsizeof(int)が加算され、32ビットプログラムでは、32ビットプログラムではintが4バイトを占めるため、4が加算される.アドレスはバイト単位であるため,ptrが指すアドレスは元の変数aのアドレスから高アドレス方向に4バイト増加した.
charタイプの長さは1バイトであるため、ptrは配列aの0番目のセルから4バイトを指し、このとき配列aの4番目のセルから4バイトを指す. 
ポインタとループを使用して配列を巡り、例を見てみましょう.
int array[20]={0};
int *ptr=array;
for(i=0;i<20;i++)
{
 (*ptr)++;//    +1
 ptr++;//       
}

この例では,整数配列中の各セルの値に1を加算する.ポインタptrは、ループのたびに1セル加算されるので、ループのたびに配列の次のセルにアクセスできます.
例を見てみましょう.
   char a[20]="You_are_a_girl";
   int *ptr=(int *)a; 
  ptr+=5;

この例では、ptrに5が加算され、コンパイラは、ポインタptrの値に5乗sizeof(int)を加算し、32ビットプログラムに5乗4=20を加算する処理を行う.アドレスの単位はバイトであるため,現在のptrが指すアドレスは5を加えたptrが指すアドレスよりも高アドレス方向に20バイト移動している.この例では、5を加えないptrは配列aの0番目のセルから4バイトを指し、5を加えるとptrは配列aの合法的な範囲外を指している.このような状況は応用上問題になるが,文法的には可能である.これもポインタの柔軟性を体現している.
上記の例では、ptrが5を減算された場合、処理過程は大きく異なるが、ptrの値は5乗sizeof(int)を減算され、新しいptrが指すアドレスは元のptrが指すアドレスよりも20バイト低いアドレス方向に移動する.
次に、もう一つ例を挙げさせていただきます.
#include<stdio.h>
int main()
{
char a[20]=" You_are_a_girl";
char *p=a;
char **ptr=&p;
 
//printf("p=%d
",p); //printf("ptr=%d
",ptr); //printf("*ptr=%d
",*ptr); printf("**ptr=%c
",**ptr); ptr++; //printf("ptr=%d
",ptr); //printf("*ptr=%d
",*ptr); printf("**ptr=%c
",**ptr); }

 
誤区一、出力答えはYとo
誤解:ptrはcharの2次ポインタであり、ptr++を実行すると;すると、ポインタにsizeof(char)が加わるので、上記の結果を出力します.これはほんの一部の人の結果かもしれません.
誤区二、出力答えはYとa
誤解:ptrは、ptr++を実行するときにchar*タイプを指します.すると、ポインタにsizeof(char*)が加算されます(この値が1だと思っている人もいるかもしれませんが、この値は4で、前の内容を参照してください)、すなわち&p+4です.では、1回の値取り演算を行うと、配列の5番目の要素を指すのではないでしょうか.出力された結果は配列の5番目の要素ではないでしょうか.答えは否定的だ.
正解:ptrのタイプはchar**で、指向するタイプはchar*のタイプで、この指向するアドレスはpのアドレス(&p)で、ptr++を実行すると;すると、ポインタにsizeof(char*)、すなわち&p+4が加算されます.では、*(&p+4)はどこを指していますか.これは神に聞いてみましょう.あるいは、彼はあなたにどこにいるか教えてくれますか.したがって、最後の出力はランダムな値であり、不正な操作である可能性がある.
 
まとめてみます.
1つのポインタptroldに整数nを加算(減算)すると、結果として新しいポインタptrnew、ptrnewのタイプはptroldのタイプと同じであり、ptrnewが指すタイプとptroldが指すタイプも同じである.ptrnewの値はptroldの値よりn乗sizeof(ptroldが指すタイプ)バイト増加(減少)します.すなわち、ptrnewが指すメモリ領域は、ptroldが指すメモリ領域よりも高い(低い)アドレス方向にn乗sizeof(ptroldが指すタイプ)バイト移動する.
 
ポインタとポインタの増減:
2つのポインタは加算演算ができません.これは不法な操作です.加算を行った後、得られた結果は方向を知らない場所を指し、意味がありません.2つのポインタは減算操作が可能ですが、同じタイプでなければなりません.一般的に配列に使われていますが、多くは言いません.