身体で覚えるポインタ型 〜Pointer Stew〜

# はじめに
　C言語を習得する上で最難関とされる<b>「ポインタ型」</b>の取り扱いについて、参考書を読んで理解しようとするより、実際のコードを見て、いじって身体で学んだ方が圧倒的に理解が早く、またイメージがつきやすいと感じたため、<b>*Pointer Stew*</b> という有名な<b>「ポインタと配列を使用するパズル」</b>（既に難しそう笑）を用いてポインタ型に関する理解を深めました。

# ポインタ型とは
　<b>「あるデータを指すデータ」</b>のことです。データのアドレス。データがどこに記憶されているか。<b>「ポインタもまたデータである」</b>と言うことが一番大事だと思います。

# Pointer Stew
　それでは、実際のコードを見ながらポインタ型の取り扱い方について見ていきます。

```c
#include <stdio.h>
1 int main()
2 {
3     char *x[4] = {"enter", "new", "point", "first"};
4     char **xp[4];
5     char ***xpp;
6     int i;   
7     for (i = 0; i < 4; i++)
8         xp[i] = x + (3 - i);
9     xpp = xp;
10  
11    printf("%s", **++xpp);
12    printf("%s ", *--*++xpp+3);
13    printf("%s", *xpp[-2]+3);
14    printf("%s\n", *--xpp[-1]+1);
15 
16    return 0;
17}
```

　サイトによって書き方はまちまちですが、見た感じ内容に大差はなかったので今回はこのサイト[^1]のコードを参照します。出力結果は何になるでしょうか…？？

[^1]: http://nob.cs.ucdavis.edu/classes/ecs030-2015-04/handouts/ptrstew.html

## 解説
### 1. char型のポインタ配列
```c
3     char *x[4] = {"enter", "new", "point", "first"};
```
　ここでは「 *x* 」が <b>*an array of pointers to characters*</b> つまり、<b>「char型のポインタ配列」（要素がchar型のポインタ、である配列）</b>であることを示しています。ここで、char型は１文字を格納するデータ型であるので、<b>char型のポインタは（複数）文字列の先頭文字のアドレスを格納しているデータ</b>です。この意味で、char型のポインタは以下のようにchar型の配列と似た使い方が可能になります。（ *s1,s2* は共に *printf* の中で先頭文字のアドレスを意味している。）

```c
char *s1  = "pointer"; printf("%s\n", s1); >>> pointer
char s2[] = "stew";    printf("%s\n", s2); >>> stew
```
　したがって、今回の場合は<b>「ポインタ型の配列」</b>のため、配列の各要素がポインタ型（上で言う *s1, s2* ）になります。ゆえに、以下のように出力することが可能です。

```c
char *x[4] = {"enter", "new", "point", "first"};
printf("%s\n", x[0]);
>>> enter
printf("%p\n", x);
>>> 0x7ffc2369d7d0 (ASLRが有効になってるため、プログラムを実行する度に変化する)
```
　なお、上の出力の２つ目は、ポインタ配列 `x` のアドレス、つまり、ポインタ配列 `x` の先頭のアドレスを表しています。（<b>`"enter"` のアドレスではありません！！ `"enter"` のアドレスは、`printf("%p", x[0])`で参照可能です。</b>）
### 2. char型のポインタ型のポインタ配列
```c
4     char **xp[4];
6     int   i;   
7     for (i = 0; i < 4; i++)
8         xp[i] = x + (3 - i);
```
　ここでは、「 `xp` 」が<b>*an array of pointers to pointers to characters*</b> つまり、<b>「char型のポインタ型のポインタ配列」</b>であることを示しています。そのため、先ほどの例を踏まえると、以下のように出力できます。

```c
char **xp[4];
int   i;
for (i = 0; i < 4; i++){
    xp[i] = x + (3 - i);
    printf("i=%d: %p\n",i,xp[i]);
}
>>> i=0: 0x7ffc2369d7e8
>>> i=1: 0x7ffc2369d7e0
>>> i=2: 0x7ffc2369d7d8
>>> i=3: 0x7ffc2369d7d0
```
　ちなみに、この時 `i` の値が 1 変わると アドレス（番地・住所）が 8 変化することが観察できますが、これの理由も、

```c
int size = sizeof(x[0]); 
printf("%d\n", size);
>>> 8
```
　であることで理解できます。char型のポインタ配列の各要素に割り当てられているサイズが *8 byte* だから、ということです。
### 3. char型のポインタのポインタのポインタ
```c
5     char ***xpp;
9     xpp = xp;
```
　ここまでくれば流れで予想できると思いますが、ここでは、「 `xpp` 」が <b>*a pointer to pointers to pointers to characters*</b> つまり、<b>「char型のポインタのポインタのポインタ」</b>であることを示していますので、以下のように出力ができます。

```c
printf("%p\n", xpp);   >>> 0x7ffc2369d7b0
printf("%p\n", *xpp);  >>> 0x7ffc2369d7e8
printf("%p\n", **xpp); >>> 0x400714
printf("%s\n", **xpp); >>> first
```
## 本題
　それでは実際に *Pointer Stew* を考えてみますが、その前に<b>「型定義時と運用時には `*` の意味が異なる（ように見える）」</b>ことについて少しだけ触れます。

　型定義時は今まで述べてきた通り、

- `char*` =「char型のポインタ」
- `char**` =「char型のポインタのポインタ」

と言うように、<b>「『\*』＝『のポインタ』」</b>と考えることができていました。

　しかし、上の `printf` 関数内での `*` の使われ方はそれとは明らかに違うことがわかります。例えば`**xpp` が `"first"`を表しているように、ポインタに `*` をつけることで、<b>「ポインタが指している対象」を意味します。</b>（つまり、ここでは `**xpp` はchar型のポインタの役割をしている。）

　<font color="red">**それでは、ここから各出力結果を考えていきます。**</font>

***
```c
11    printf("%s", **++xpp);
```
　これは、9 行目の式 `xpp = xp` から分かる通り、 `xpp` が「char型のポインタ型のポインタ配列 `xp` 」の先頭アドレスを意味しています。「`++`」は`+1`と同義（足すタイミングが異なるだけ。後ろに付く場合もある）だと考えれば、先頭から２つ目のアドレスを指しており、（ここまでで `++xpp` ）そこに `*` が２つ付くことによって、 `xp[1] = x + (3 - 1) = x + 2` 、`char *x[4] = {"enter", "new", "point", "first"}` からここでの出力は <b>`"point"`</b>であることが分かります。
***
```c
12    printf("%s ", *--*++xpp+3);
````
　これは、「`++`」の理解が多少必要になります。`i++` ≒ `i=i+1` であるから、先の計算で `xpp` は １ インクリメントされています。したがって、ここで更に１インクリメントすることによって、「char型のポインタ型のポインタ配列 `xp` 」の<b>「３つ目」</b>のアドレスを指していることになります。（ここまでで `++xpp` ）

　そこに`*`が１つ付くことによって、 `xp[2] = x + (3 - 2) = x + 1`、これを`--`で１デクリメントすることによって、「char型のポインタ配列 `x` 」の先頭のアドレスを示します。（ここまでで `--*++xpp`）

　更に `*` が付くことによって先頭の要素 `"enter"` の先頭のアドレスを意味し、最後に3足すことで４文字目 `"e"` のアドレスを意味します。そこから `printf` するので、ここでの出力は <b>`"er"`</b>であることが分かります。

***
```c
13    printf("%s", *xpp[-2]+3);
```
　これは、`xpp[-2]` の意味をきちんと理解する必要があります。「 `xpp` の後ろから２つ目の要素だな！」と思うかもしれませんが（僕もそう思いました）、残念ながらそれは間違いです。正しくは、<b>`xpp` の指すアドレスに `[]` の中の数 （今回は `-2`） を足したアドレスを指す</b>と言うことを意味しています。（他にも `*(ポインタ変数 + 要素番号)` なんてものもあるみたいです。)

　先ほどまでですでに `xpp` は２インクリメントされているので、`-2`してちょうど元々 `xpp` が指していたアドレスを指します。つまり、`xp[0] = x + (3 - 0) = x + 3` そこに `*` が付くことによって `"first"` の先頭アドレスを指し、先ほどと同様にして出力は<b>`"st"`</b>となります。

***
```c
14    printf("%s\n", *--xpp[-1]+1);
```
　最後は<b>`"ew"`</b>です。

　と言うのはあまりにも雑すぎるので一応解説も載せておくと、`xpp[-1]` が先程と同様にして `xp[1] = x + (3 - 1) = x + 2` を指し、そこから１デクリメントして `*` が付くことによって `"new"` の先頭アドレスを指し、最後に `+1` をするので２文字目から出力が始まり、結果<b>`"ew"`</b>となります。

　<font color="red"><b>以上より、プログラムを通した出力は `"pointer stew"` となります。</b></font>

# 最後に
　ポインタ型を難しくしている要因は、記号の使い方だと感じています。例えば

```c
3     char *x[4];
4     char **xp[4];
5     char ***xpp;
```
　というように定義しますが、これだと結局 `*x` , `xp` , `xpp*` が何を表すものとして定義されたのかがわかりにくい気がします。多少の誤差かもしれませんが、

```c
3     char*   x[4];
4     char**  xp[4];
5     char*** xpp;
```

　と型を表す方にポインタ型である記号をつけた方が格段にわかりやすくなると思います。また、先にも記述しましたが、<b>型定義時に使う `*` と関数内で使われる `*` が同じ記号</b>なのも苦戦するポイントだと感じました。<b>「同じような役割を持つ記号は同じ記号にする」</b>と言う考え方が働いているようですが、かえってわかりにくくなっている気がします…。（他に理由があったら教えてください。）

# おわりに

　僕自身間違った認識をしている部分もあるかと思いますので、何かミス等あればご指摘よろしくお願いします🙇‍♂️