- ベストアンサー
int型ポインタの加算
void foo() { int *ptrInt=0; char *ptrChar=0; ptrInt++; ptrChar++; } Windows2000上で、上記を実行すると ptrIntは4になります。 ptrCharは1になります。 なぜでしょうか。 32ビットとはいえ、 ptrIntとptrCharはアドレスを示しますよね。 アドレスに1加算するのだから、 int型、char型に関係なく、 いずれも1になるべきだと思います。 int型のポインタの場合示すデータは4バイトなので、 ポインタ1加算は、4(バイト)加算になるということでしょうか。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
mtsed さんは「ポインタ」とは「アドレス」であると思っているようですね。 まず、ポインタは「型」であると覚えたほうが良いと思います。 そして、ただの「ポインタ型」というものがあるわけではなく、必ず「何かの型へのポインタ型」になるわけです。 ですので、「char型へのポインタ型」と「int型へのポインタ型」とは別の型になるわけです。 そして、ポインタ演算をすると、この「○○型へのポインタ型」の○○型のサイズ分だけアドレスが加算されるわけです。 ちなみに、一般に単に「○○型へのポインタ」と言った場合、次の3つのいずれかの意味で使われていると思います。 1. ○○型へのポインタ型 2. ○○型へのポインタ型の変数 3. ○○型へのポインタ型の値 私は意識して使い分けるべきだと思うのですが、私の周りをみると結構いい加減な人が多いのも事実のように思います。 たとえば、以下の例の場合を考えて見ます。 ---------------------------------------- int *hoge_ptr; int hoge; hoge_ptr = &hoge; ---------------------------------------- この場合、 「int *」が「int型へのポインタ型」をあらわしています。 「hoge_ptr」は「int型へのポインタ型の変数」として定義されます。 そして、hoge は「int型の変数」なので、&hoge は「int型へのポインタ型の値」を持つことになります。 hoge_ptr は「int型へのポインタ型の変数」ですから、当然「int型へのポインタ型の値」しか設定することができません。 そうしないと、*hoge_ptr としたときに正しい値を読み出せないですよね? このあたりの話は問題ないと思いますが…大丈夫ですよね? # 大丈夫な場合は、大変失礼いたしました。 ですので、hoge_ptr++ としたときに、アドレスが 1バイトしか進まなかった場合、*hoge_ptr で読み出せる値は、意味のない値になってしまうことになります。 意味のある値を読み出すためには、int型のサイズ分 (32ビットであれば、4バイトですよね) アドレスを加算しなければいけないわけです。 こんな説明でいかがでしょうか。
その他の回答 (4)
- seven_star
- ベストアンサー率33% (1/3)
皆さんの言うとおりです。 int は4バイト charは1バイトです。 このように考えるとわかりやすいです。 縦に箱がずらっと並んでいることを想像してください。 int は4バイトなのでひとつの*ptrIntにたいして4つの箱が割り当てられます。 よって初期状態で*ptrIntは[0],[1],[2],[3]がわりあてられそのうちの[0]に、上記のプログラムによると0が代入している状態です。 ここでptrInt++をすると、次の4つ箱に進みます。 よって[4],[5],[6],[7]が割り当てられ、 そのうちの[4]を示している状態です。 なので、ここでアドレスを表示すると4になるわけです。
お礼
ありがとうございます。
- fibre102
- ベストアンサー率20% (6/29)
ポインタとただのアドレスの違いはまさにこの点だと思います。たとえば構造体のポインタでも同じで、+1すると構造体サイズ分アドレスが進みます。 ポインタは構造体の先頭アドレスを指すだけでなく、そのポイントした領域のサイズ(と構造)まで表します。 この辺をおさえておけば、ポインタも扱いやすくなると思います。
お礼
なるほどです。 ありがとうございます。
- nitscape
- ベストアンサー率30% (275/909)
>int型のポインタの場合示すデータは4バイトなので、 >ポインタ1加算は、4(バイト)加算になるということでしょうか そういうことになります。 ptrInt++で1ずつ加算されるとどうなるか?4ずつ加算されるとどうなるか?を実際のプログラミング上でのポインタの使い方と絡めて考えるとよりポインタのことが理解できると思います。 int pnInt[2]; char pbChar[2]; として考えると分かりやすいと思います。この場合もchar*やint*で宣言したときと同じです。 こうして &(pnInt[0]) &(pnInt[1]) &(pbChar[0]) &(pbChar[1]) のようにアドレスを見るとcharの場合はアドレスが1差なのに、intの場合は4差になります。 sizeof(int); sizeof(char); でintデータとcharデータの大きさを見るとそれぞれのデータサイズが分かります(4と1)(実際にはプラットフォームによってintは2など違うこともあります)。この大きさごとにアドレスも大きくなります。 int*を4ずつではなく、1ずつ大きくするには。。。 ((char*)ptrInt)++; のようにします。*ptrIntに数値を代入してアドレスを1ずつ動かして値を出力したりすると面白いかもしれません。
お礼
なるほどキャストすれば、1ずつできるのですね。 ありがとうございます。
- kameDK
- ベストアンサー率22% (17/75)
その通りです。 配列を考えた場合ポインタが型に関係なくインクリメントしたときに1しか進まないのでは、int型の配列では正しく値を取り出せなくなります。 ポインタに型を宣言するのはそのポインタの指すものがどれだけの範囲を占有しているかを示しています。 ポインタはその型を元に次に読み出し始める番地に移動し、そこからデータとして扱います。
お礼
ご回答ありがとうございます。 1インクリメントでは配列は確かに取り出せないですね。
お礼
ご丁寧なご説明ありがとうございます。 よくわかりました。