目次
ポインタとは
ポインタは、変数のアドレス(住所)を格納する変数です。
ポインタを使うことで、間接的に他の変数の値を参照・変更したり、配列や関数を効率的に扱うことができます。
以下は、ポインタを使用したコードです。
#include <stdio.h>
int main(void)
{
// 1 変数への代入
int a = 10;
printf("%d\n", a); // 10
// 2 ポインタ変数
int *p; // ポインタ変数pを宣言
p = &a; // pにaのアドレスを代入
printf("%p\n", (void *)p); // 0061FF18 アドレス
// 3 間接参照(*演算子)
printf("%d\n", *p); // 10 間接参照 *演算子
// 4 値の変更も可能
*p = 20; // 20に変更
printf("*p = %d\n", *p); // *p = 20
printf("a = %d\n", a); // a = 20
return 0;
}
上記コードの説明
// 1 変数への代入
int a = 10;
printf("%d\n", a); // 10
変数aに値を代入しています。&aとした場合は、変数aのアドレスになります。
// 2 ポインタ変数
int *p; // ポインタ変数pを宣言
p = &a; // pにaのアドレスを代入
printf("%p\n", (void *)p); // 0061FF18 アドレス
pはint型のオブジェクトを指すことができるポインタ変数です。宣言の*は変数名の一部ではなく、pの型がintへのポインタであることを表します。
宣言のint *p;に出てくる*と、後で使う*pの*は別の意味です。前者は型の一部、後者は指す先をたどる演算子です。
なおint* p;と書いても文法上は同じですが、int* p,q;とするとqはポインタにならないため(*が型側に付いているように見えてしまい、int* p, q;としたときに両方ポインタだと錯覚しやすくなるため)、int *p;の書き方が推奨されます。
両方ポインタの例:
int *p, *q;
注意点
int *p;と宣言しただけのポインタには、意味のない不定値が入っています。この状態で*pを使うと、プログラムがどこを書き換えるか誰にも分かりません。運が良ければ即座に落ちますが、運が悪いと壊れたまま動き続けます。
指す先がすぐ決まるなら、宣言と同時に代入します。
int a = 10;
int *p = &a; // 宣言と同時に指す先を決める
すぐ決まらないならNULLを入れておきます。
int *p = NULL; // 「まだ何も指していない」ことを明示する
if (p != NULL) { // 使う前に必ず確認する
*p = 20;
}
NULLはどのオブジェクトも指さないことを表す特別な値で、<stdio.h> などをインクルードすれば使えます。p = NULL; としておけば、少なくとも未設定であることをプログラム自身が判定できます。不定値のままでは、この判定すらできません。
// 3 間接参照(*演算子)
printf("%d\n", *p); // 10 間接参照 *演算子
*pは、pが指す先にある値、つまりaの値を取り出すことを意味します。
// 4 値の変更も可能
*p = 20; // aの値を20に変更
printf("*p = %d\n", *p); // *p = 20
printf("a = %d\n", a); // a = 20
pが指している先、つまり変数aに20を代入しています。p自身の値(aのアドレス)は変わりません。
※13行目の%pの出力形式は処理系依存で、0061FF18のような値は環境ごとに変わります(実行のたびに変わることも普通です)。
配列の場合
#include <stdio.h>
int main(void)
{
int a[3] = {10, 20, 30};
int *p = a;
printf("%d\n", a[0]); // 10
printf("%d\n", a[1]); // 20
printf("%d\n", a[2]); // 30
printf("%d\n", *p); // 10
printf("%d\n", *(p + 1)); // 20
printf("%d\n", *(p + 2)); // 30
printf("%p\n", (void *)p); // 0061FF10 アドレス
printf("%p\n", (void *)(p + 1)); // 0061FF14 アドレス
printf("%p\n", (void *)(p + 2)); // 0061FF18 アドレス
return 0;
}
int *p = a;は、
int型の値を指すポインタ変数pを作り、配列aの先頭要素のアドレスを代入しています。
配列名aは、多くの場面で配列の先頭要素 a[0] のアドレスとして扱われます。
ポインタ変数への代入で普通の変数では、以下のように&aが必要ですが、
int a = 10;
int *p;
p = &a;
配列では以下のように&は不要です。
int a[3] = {10, 20, 30};
int *p = a;
※15-17行目の%pの出力形式は処理系依存で、0061FF18のような値は環境ごとに変わります(実行のたびに変わることも普通です)。
関数の場合
#include <stdio.h>
void change(int *p)
{
*p = 20;
}
int main(void)
{
int a = 10;
printf("%d\n", a); // 10
change(&a);
printf("%d\n", a); // 20
return 0;
}
12行目は、関数changeに、変数aのアドレスを渡しています。
3行目は、int型を指すポインタを引数として受け取る関数です。
5行目は、そのアドレスにある値を書き換えています。
関連の記事
