ポインタの&と*

番地を入れておく変数

前回、&score で変数の番地を取り出せることを見ました。取り出した番地は、その場で使い捨てにする必要はありません。番地も 1 つの値なので、変数に入れて持ち歩けます。

番地を入れるための変数を ポインタ と呼びます。宣言は型名のうしろに * を付けます。

int score = 80; int *p; // int の置き場所の番地を入れる変数 p = &score; // score の番地を入れる

int *p; は「p は int を指すポインタです」と読みます。宣言と代入をまとめて int *p = &score; と書くこともできます。

なぜ型を書くのか

番地の入れ物なのに、どうして int と書く必要があるのでしょうか。前回の最後に触れたとおり、番地は先頭のロッカー番号でしかないからです。そこから何バイト読めばよいか、読んだビット列をどう解釈すればよいかは、番地だけでは決まりません。int * なら 4 バイトを整数として、double * なら 8 バイトを小数として読む、という指示が型に入っています。だから double の番地を int * に入れることはできません。

* で中身を読む

ポインタが持っている番地の先を見るには、* を付けます。これを 間接参照 と呼びます。

printf("%d\n", *p); // p が指している場所の値、つまり 80

宣言のときの * と、使うときの * は見た目が同じで紛らわしいのですが、役割は別物です。宣言の * は「これはポインタです」という印、使うときの * は「指している先を見ろ」という命令です。

* を左に書くと書き換えになる

*p は読むだけでなく、代入の左辺にも置けます。

*p = 95; printf("%d\n", score); // 95 になっている

p を通して score そのものを書き換えました。score という名札を使わずに値を変えられた、という点がポインタの本質です。ここが次の 2 回、scanf の正体と、関数から呼び出し元を書き換える話につながります。

指す先を決める前に使わない

int *p; と宣言しただけのポインタには、何の番地が入っているか分かりません。前章までの初期化していない変数と同じで、ごみの値が入っています。その状態で *p を読み書きすると、まったく関係のない場所を触ることになり、プログラムはたいてい異常終了します。

どこも指していないことを示したいときは int *p = NULL; と書いておく習慣があります。NULL は「有効な番地ではない」と決められた特別な値なので、if (p != NULL) で使ってよいかを確かめられます。まずは、指す先を決める前に * を使わない、という 1 点だけ守ってください。

では、点数をポインタ経由で読み書きしてみましょう。

要件

  1. int score に 80 を入れる
  2. int *p に score の番地を入れる
  3. *p で読んだ値を 「pが指す値は80点です」 の形で表示する
  4. *p への代入で score を 95 に書き換え、score を 「書き換えたあとのscoreは95点です」 の形で表示する

入出力例

main("") → "scoreの値は80点です pが指す値は80点です 書き換えたあとのscoreは95点です"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.c
学習モード

メモ

ポインタの&と*

⌘S で保存