C言語のポインタを日本一わかりやすく解説する〜導入編〜

## はじめに
　C言語は、私がエンジニアになるにあたって一番最初に勉強~~した~~させられたプログラミング言語です。「プログラミングって楽しいかもしれない...！」と思い始めた矢先に登場するこの**ポインタ**と呼ばれる単元は、当時のプログラミング初心者であった私を挫折させました。正直に言ってしまえば**くっそ難しい**です。
　それでも乗り越えたい...！という初心者エンジニアさんにこの記事をお送りしたいと思います。

## ポインタとは？
　ポインタ（pointer）と聞くと、プレゼンテーション等でよく使われるこれを思い浮かべませんか？
![images.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298123/8f527152-6a01-70b5-8a8a-af2fac69b4bd.jpeg)
　手に持ってスライド中の大切なところを**指し示すため**に使われるイメージの強いポインタですが、この「**指し示す**」というのが非常に重要です。C言語においてもレーザーポインタのように指し示すことができます。

## ポインタが指し示すもの
　プレゼン中でスライドの今話している該当箇所をレーザーポインタで指し示すのと同じように、ポインタは**とある場所の1点を指し示す**ことができます。
　C言語におけるポインタは**なんの場所**の1点を指し示すかというと、**アドレス(address)**を指し示します。そしてなんのアドレスかというと、**オブジェクト(object)**のアドレスです。
　さらに噛み砕いていきます。C言語では変数と呼ばれるものを宣言することができました。例えば、次のようなプログラムにおいて

```c:variable.c
#include<stdio.h>

int main(void)
{
    int x;              /* xはint型の変数 */
    x = 5;              /* 変数xに5を代入 */

    printf("x:%d", x);  /* xの値を表示 */
    return 0;
}
```

　`x`というのが変数です。変数とは、数値や文字を格納するための「箱」みたいなものであり**オブジェクト**です。
　ところでこのオブジェクトは、当然作ったからには5を代入することができたり、その変数の値を表示できたりと色々なことができますが、このオブジェクト自体そもそもどこに存在するのでしょう？
　正解は**メモリ**です。メモリとは、広大な空間を持つ記憶域であり、その中の1点にオブジェクトが存在しています。広大な空間の中の1点に存在するわけですから、このオブジェクトを端から端まで探していくのは極めて大変な作業です。そこで**アドレス**という、いわば住所がその1点についています。一度ここで図を使って整理しましょう。
![図1.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298123/a31f019f-78ae-550f-d60b-0f83a64f52ad.jpeg)
　この図では広大なメモリの中の1点のアドレス「0x7ffeed0dca38」にオブジェクトのxが存在し、その中に数値の5が代入されていることになります。実際にプログラムを作って確認してみましょう。

```c:variable.c（改変）
#include<stdio.h>

int main(void)
{
    int x;              /* xはint型の変数 */
    x = 5;              /* 変数xに5を代入 */

    printf("x:%p", &x);  /* xのアドレスを表示 */
    return 0;
}
```

　このプログラムをコンパイルし実行すると、おそらく人それぞれで異なる値が表示されると思います。私の場合は`x:0x7ffeed0dca38`になりました。
　簡単にプログラムの解説をすると、`printf`による表示の際の「**&**」は**アドレス演算子**と呼ばれるもので`x`のメモリ上のアドレス値を表します。そして、これを表示するためには`%p`を使って指定したオブジェクトのアドレスを出力します。

　さて、ここまで色々と書いてきましたが、肝心の**ポインタ**の話に戻りましょう。最初の方でポインタは**オブジェクトのアドレスを指し示している**ということを書きました。上の図において、オブジェクト`x`のアドレス`0x7ffeed0dca38`を指し示しているのは、**緑の矢印（→）**ですね。ポインタは**オブジェクトのアドレスを格納している**ことになります。イメージはこんな感じです。
![図2.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298123/d3a7afe1-1952-0587-b41d-99d440b7f447.jpeg)
　少し情報量が多いですね。整理しましょう。オブジェクト`x`がありますね。これのアドレス`0x7ffeed0dca38`を**ポインタ変数**と呼ばれる箱に格納します。このポインタ変数を図では`p_x`とおいています。
　この`p_x`は当然ながらオブジェクト`x`のアドレス`0x7ffeed0dca38`を持っているため、この情報を表示することができます。これに加えて、このポインタ変数が指し示している1点のオブジェクト`x`の**格納値**も表示することができるのです。xの格納値5を出力するためには、**`*p_x`**のように米印（アスタリスク）を置きます。プログラムで確認してみましょう。

```c:pointer.c
#include<stdio.h>

int main(void)
{
    int x;                      /* xはint型の変数 */
    x = 5;                      /* 変数xに5を代入 */

    printf("   x:%d\n", x);     /* xの値を表示 */
    printf("  &x:%p\n", &x);    /* xのアドレスを表示 */

    int *p_x;                   /* p_xはポインタ変数 */
    p_x = &x;                   /* ポインタ変数p_xにxのアドレスを代入 */

    printf(" p_x:%p\n", p_x);   /* p_xの値を表示 */
    printf("*p_x:%d\n", *p_x);  /* *p_xの値を表示 */
    return 0;
}
/*----実行結果------
   x:5
  &x:0x7ffeed0dca38
 p_x:0x7ffeed0dca38
*p_x:5
---------------- */
```

　ポインタが難しいと呼ばれる所以はこのプログラムに詰まっています。上2つの実行結果は先ほどのプログラムと全く同じです。ポインタ変数は普通の変数同様に宣言ができますが**`*`**マークがつきます。つくった`p_x`には先ほどの図のようにオブジェクト`x`のアドレスを代入します。このとき、**`*p_x`ではなく`p_x`に代入**しています。下の`printf`にて出力される結果をみてみましょう。`p_x`には**オブジェクトxのアドレス**、`*p_x`には**オブジェクトxの格納値**が出力されます。

　`&`と`*`の区別がしづらいので整理しましょう。

| 演算子 | 名前 | 説明 |
|:----------------|:-----------------|:------------------|
| & | アドレス演算子 | オブジェクトのアドレスを取り出す |
| * | 関接演算子 | それが指し示すものの中身 |

　`p_x`はオブジェクト`x`を指し示すポインタ変数であり、アドレスが格納されています。`*p_x`という記述にするとその指し示したオブジェクトの中身、すなわち格納された**5**を得ることができます。

## 実は...
　先ほどのプログラムにおけるポインタ変数`p_x`の宣言ですが、実は下記の記述でも全く問題がありません。寧ろ理解がしやすいと思います。

```
    int* p_x;
    p_x = &x;
```

　`int *p_x`という書き方だと、int型なの？と困惑された方が多いかと思います。確かに`p_x`という変数はint型のオブジェクトのアドレスを指し示すデータなので、本来であれば`int* p_x`と書くべきです。しかし、一行で複数の変数を宣言しようとした時に、その書き方だとかえって理解し難くなってしまうので、`int *p_x`が一般になりました。

```
    int* p_x, p_y;
    /* int*型のp_x, int型のp_yを用意してしまう */
```

## 最後に
　今回は導入編なので、ここまでにしておきたいと思います。ポインタはまだまだ奥が深く難しいです。なるべく早めに記事にしたいと思います。完成次第、下記にリンクを貼っておきます。