【C++】ポインタ演算とは?配列とポインタでアドレスを操作する基本

目次

はじめに

前回の記事では、「配列の名前は、配列の先頭要素を指すポインタのように振る舞う」というC++の重要な性質を学びました。では、その「ポインタのようなもの」に対して、もし足し算や引き算をしたら、一体何が起こるのでしょうか?

これが、今回解説する「ポインタ演算」の世界です。ポインタ演算を理解すると、なぜfor文で配列の全要素にアクセスできるのか、その裏側の仕組みが手に取るように分かります。


ポインタに1を足すと、アドレスはどうなる?

素直に考えると、メモリアドレス(数値)に1を足すのだから、「アドレスの値が1だけ増える」と思ってしまいますよね。しかし、C++の世界ではそうはなりません。

ポインタ演算の最も重要なルールはこれです。

ポインタに整数 n を足すと、アドレスは n バイト進むのではなく、「指し示しているデータ型 n 個分」進む。

int型の配列を指すポインタに1を足した場合、int型1個分のサイズ(多くの環境で4バイト)だけアドレスが進みます。つまり、配列の次の要素を指すようになるのです。

これを、アパートの部屋番号で考えてみましょう。ポインタは「部屋の住所」を知っています。ポインタに+1するということは、「隣の部屋の住所」を尋ねるのと同じことなのです。


実際のコードでポインタ演算を確認

C++コード例

このルールが本当かどうか、実際のコードで確かめてみましょう。numbersという配列を使って、ポインタ演算の結果がどのようになるかを出力します。

#include <iostream>
using namespace std;

int main() 
{
    int numbers[5] = {100, 200, 300, 400, 500};

    cout << "--- ポインタ演算の基本 ---\n\n";

    // 配列名「numbers」は先頭要素のアドレスを指すことを再確認
    cout << "numbers のアドレス:\t" << numbers << "\n";
    cout << "&numbers[0] のアドレス:\t" << &numbers[0] << "\n\n";

    // 「numbers + 1」でアドレスがどう変わるかを確認
    cout << "numbers + 1 のアドレス:\t" << numbers + 1 << "\n";
    cout << "&numbers[1] のアドレス:\t" << &numbers[1] << "\n\n";

    // ポインタ演算の結果をデリファレンス(*で値を取得)
    cout << "*(numbers + 1) の値:\t" << *(numbers + 1) << "\n";
    cout << "numbers[1] の値:\t" << numbers[1] << "\n";

    return 0;
}

結果の解説

このコードを実行すると、以下のような結果が得られます。(アドレス値は実行環境により異なります)

--- ポインタ演算の基本 ---

numbers のアドレス:     0x7ffee...a0
&numbers[0] のアドレス: 0x7ffee...a0

numbers + 1 のアドレス: 0x7ffee...a4
&numbers[1] のアドレス: 0x7ffee...a4

*(numbers + 1) の値:    200
numbers[1] の値:        200
  • 1つ目のブロック: numbers&numbers[0]が同じアドレスであることを再確認しています。
  • 2つ目のブロック: ここが核心です。numbers + 1の結果は、numbersのアドレスに単純に1を足した...a1にはならず、...a4となっています。これはint型が4バイトの環境で、きっちりデータ1個分アドレスが進んだことを示しています。そして、そのアドレスは&numbers[1](2番目の要素のアドレス)と完全に一致します。
  • 3つ目のブロック: numbers + 1が2番目の要素を指すアドレスなので、*(numbers + 1)とデリファレンスすれば、2番目の要素の値200が取得できます。これはもちろんnumbers[1]の値と同じです。

[]*() の驚くべき関係

ここまでの解説で、鋭い方は気づいたかもしれません。

  • numbers[1]
  • *(numbers + 1)

この2つの書き方は、全く同じ意味だったのです。

一般化すると、配列名[n] という見慣れた書き方は、C++の内部では *(配列名 + n) というポインタ演算の形で解釈されています。普段何気なく使っている角括弧[]は、実はポインタ演算を分かりやすくするための「シンタックスシュガー(糖衣構文)」だった、というわけです。


まとめ

今回は、C++の強力な機能である「ポインタ演算」の基本を解説しました。

  • ポインタに整数nを足すと、n個先の要素を指すアドレスになる。
  • これにより、配列の各要素を順番に辿ることができる。
  • 配列名[n]という書き方は、内部的には*(配列名 + n)として処理されている。

このポインタ演算の仕組みこそが、配列とポインタの密接な関係性の核心です。この基本を理解すれば、C++のメモリ操作に対する解像度が格段に上がるはずです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次