C++ with Windows API講習/ポインタ

概要

本章では、ポインタを通してアドレスの使い方を学びます。
C++の中でも低層に位置する機能ではありますが、かなりややこしい構文を使います。

重要語

ポインタ

アドレスを保存する変数

間接参照

アドレスを変数のように扱うこと

値渡し

数値データをそのまま引数にすること

ポインタ渡し

データを指すポインタを引数にすること

必要語

アドレス

メモリ内の位置を表す数値

関数

結果を返す、動作のまとまり

引数

関数に渡す値

ポインタ

まずは以下のプログラムを実行してみましょう。
ポインタ
#include <Windows.h>
#include <string>

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) {
    //100で初期化
    int a=100;
    //int型へのポインタ
    int* ptr;
    //aのアドレスを代入する
    ptr = &a;

    //ここでの*ptrはaと同じ意味になる
    MessageBoxW(NULL, std::to_wstring(*ptr).c_str(), L"(*ptr)の値", MB_OK);

    //a = 200;と同じ
    *ptr = 200;

    //aが書き換えられている
    MessageBoxW(NULL, std::to_wstring(a).c_str(), L"aの値", MB_OK);

    return 0;
}

ポインタの宣言

アドレスを保存する変数のことを、ポインタといいます。
ポインタは型名* ポインタ名という構文で宣言します。
型名には、そのポインタが指す値の型を書きます。

ポインタの型

C++の変数には型がありますが、メモリには型がありません。
そして、値の符号化方法は型によって違います。
別の型として読み出せば、全く異なる意味になってしまいます。
ここで、ポインタが値の型を表すことで、読み書き時に型を間違える事故を防げます。
また、int* ptr;で宣言した変数を、int型へのポインタptrと呼びます。

変数のアドレス

さて、ポインタに入れるためのアドレスはどうやって取得するのでしょうか。
多くのC++の変数はメモリ上にあり、それぞれにアドレスがあります。
アドレスを取得するには、&変数名という構文を用います。
上の例文では、int型変数aのアドレスを、int型へのポインタptrに代入しています。

間接参照

ポインタに入っているアドレスは、変数のように扱うことができます。
間接参照
#include <Windows.h>
#include <string>

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) {
    //通常のint型変数
    int a;
    //int型の変数を指すポインタ
    int* ptr;
    //aのアドレスを代入する
    ptr = &a;

    //std::wstringはアドレスを受け取らないのでint型にキャストする
    MessageBoxW(NULL, std::to_wstring((int)ptr).c_str(), L"アドレス", MB_OK);

    return 0;
}

構文

*ポインタ名で、ポインタが指すメモリを変数のように扱うことができます。
例文では、ptrが指すメモリをaも使っています。
そのため、*ptraと同じように扱うことができます。

ポインタ渡し

コンピュータの関数の引数にできるのは、数値だけです。
int型などであれば、そのまま渡すことができます。
しかし、std::wstring型のようなデータは、そのまま渡すことができません。
ですから、コンピュータの関数の引数の渡し方には2種類があります。

値渡し

先ほど述べた、int型のほかに、double型などの数値型は、そのまま引数にすることができます。
このことを、値渡しといいます。

ポインタ渡し

一方、文字列型のような、数値1つで表せない型は、一度メモリに保存し、そのアドレスを引数とします。
こちらの方法を、ポインタ渡しといいます。