導入
前のレッスンで、変数はメモリ上に「住所(アドレス)」を持つと学びました。ポインタは、その住所を入れておくための変数です。「住所を書いたメモ」だと考えてください。
説明
ポインタを使うには、2つの記号を覚えます。ここで & と * の役割を混同しないことが最初の関門です。
&変数… その変数の住所を取り出す(アドレス演算子)。**「&=住所を聞く」**と覚えましょう。*ポインタ… その住所に置かれている中身を読み書きする(間接参照)。**「*=中身をたどる」**と覚えましょう。
#include <stdio.h>
int main() {
int x = 5;
int *p = &x; // pは「xの住所」を持つポインタ
printf("xの値 : %d\n", x); // 5
printf("xの住所 : %p\n", (void *)&x); // 例: 0x... (番地)
printf("pの中身 : %p\n", (void *)p); // &xと同じ番地
printf("*p : %d\n", *p); // 5(pの指す先の中身)
*p = 10; // *pへの代入は、その住所にあるxを書き換える
printf("x = %d\n", x); // 10
return 0;
}
図にすると、ポインタ p は x を「指している」だけの、別の小さな箱です。p の中身は x の住所(番地)で、*p はその矢印をたどった先=x そのものを表します。
flowchart LR p["ポインタ p<br/>中身 = 1002(xの番地)"] -->|"*p でたどる"| x["1002番地<br/>x = 5"]
int *p は「int を指すポインタ」という宣言です。p = &x で x の住所を入れ、*p で x の中身にアクセスします。*p = 10; は「p が指している先=x」を書き換えるので、x 自身が 10 になります。
ポインタは「別名でその変数を操作するリモコン」だと考えると分かりやすいです。手元のリモコン(p)が、離れた場所のテレビ(x)を操作するイメージです。
flowchart LR A["&x<br/>(xの住所を取り出す)"] --> P["pに住所を保存"] P --> B["*p<br/>(住所をたどって中身にアクセス)"] --> X["xを読む/書く"]
& と * は、いつも「反対の向き」だと考えると混乱しにくいです。&変数 は「変数 → 住所」、*ポインタ は「住所 → 変数(中身)」という、たどる方向がちょうど逆になっています。
やってみよう
*p = 10; の値を変えたり、x を直接書き換えたりして、x と *p がいつも同じ値を指していることを確かめましょう。&x と p を表示して、同じ番地になっていることも見てください。
演習
int n = 3; を指すポインタ p を作り、*p を使って n の値を 99 に書き換え、n を表示してください(結果は 99)。
ヒント1を見る
int *p = &n; のあと *p = 99;、最後に printf("%d\n", n);。