ポインタ変数 / *と&の使いかた

参考: 日経ソフトウエア 2019年 5 月号, pp.90-97

  • 変数に割り振られたアドレスを取り出すときは&変数という構文を使う。
  • ポインタ変数も変数なので、自身に代入されたアドレスとは別に、自身に割り振られたアドレスがある。
  • ポインタ変数を宣言するときは型 *ポインタ変数という構文を使う。
  • ポインタ変数のポイント先に存在している値を参照するときは*ポインタ変数という構文を使う。
#include <iostream>
using namespace std;

int main() {

    //////////////////////////////////////////////////////////////////////////////////////
    char a; // char型変数を宣言する。このタイミングで変数aにアドレスが割り振られる。
    a = 80; // 変数aに何かを代入する。

    // 普通の変数からは下の2つが取り出せる(と考えることにする)。ついでにそれぞれのサイズも確認しておく。
    printf("1. char型変数に代入されたデータ: %d\n", a);
    printf("2. char型変数に割り振られたアドレス: %p\n", &a);

    printf("3. char型変数のサイズ(バイト数): %d\n", sizeof(a));
    printf("4. char型変数に割り振られたアドレスのサイズ(バイト数): %d\n", sizeof(&a));

    //////////////////////////////////////////////////////////////////////////////////////

    char *p; // char型変数のアドレスを代入するためのポインタ変数pを宣言する。このタイミングでポインタ変数pにアドレスが割り振られる。
    p = &a;  // ポインタ変数pに何かのアドレス(ここではchar型変数aのアドレス)を代入する。

    // ポインタ変数からは下の3つが取り出せる(と考えることにする)。ついでにそれぞれのサイズも確認しておく。
    printf("1. ポインタ変数に代入されたアドレス: %p\n", p);
    printf("2. ポインタ変数のポイント先に存在しているデータ: %d\n", *p);
    printf("3. ポインタ変数に割り振られたアドレス: %p\n", &p);

    printf("4. ポインタ変数のサイズ(バイト数): %d\n", sizeof(p));
    printf("5. ポインタ変数のポイント先に存在しているデータのサイズ(バイト数): %d\n", sizeof(*p));
    printf("6. ポインタ変数に割り振られたアドレスのサイズ(バイト数): %d\n", sizeof(&p));

    //////////////////////////////////////////////////////////////////////////////////////

    a = 100; // すなわち上の変数aへは、直接何かを代入すること(メモリに記憶してあるデータを変数経由で間接的に書き換えること)もできるし、
    printf("%d\n", a);
    printf("%d\n", *p);

    *p = 110; // ポインタ変数経由で間接的に何かを代入すること(メモリに記憶してあるデータを直接書き換えること)もできる。  
    printf("%d\n", a);
    printf("%d\n", *p);

    //////////////////////////////////////////////////////////////////////////////////////


    return 0;
}

f:id:ti-nspire:20190611095533p:plain:w800
上の実行例は32ビット版のコンパイラを使っているのでアドレスは型によらず全部4バイトであるが、下のように64ビット版を使えばアドレスは型によらず全部8バイトになる。
f:id:ti-nspire:20190611095621p:plain:w800