Goで学ぶポインタとアドレス

# Goで学ぶポインタとアドレス
Goってシンプルで書きやすいですよね。
しかし、シンプルなGoでもいくつか躓きやすいポイントがあると思っています。
その最初のポイントがポインタではないでしょうか。特に、ポインタの概念が存在しない言語から始めた人にとっては、なかなかとっつきにくいものだと思います。そこで今回は、なんとなく使っていたポインタを、ちゃんと理解するためのエントリを書きました。ポインタをちゃんと理解しようとすると、その前提として知らなければならないことが多々あり、そこから説明するので、やや遠回りをした説明になっています。
「これちげえじゃねえか」とか、「ここわかりにくいぜ」っていうのがあったら、ご教授ください。

※ 技術的な話は「です、ます」調よりも「である、だ」調の方が書きやすいので、以降は「である、だ」調で書きます。

# 前提知識Part
先ほど述べたとおり、ポインタを理解しようとすると、前提知識が必要になってくる。
まずは、その前提知識を説明したいと思う。

## プログラムのコンパイルから実行までの流れ
何かしらの高級言語(GoとかJavaとか)で書かれたソースコードはそのままではそのプログラムをPCで実行することはできない。
ではどうするかというと、高級言語で書かれたソースコードをコンパイラでコンパイルし、コンピュータがプログラムを実行できるような形にする。
この「実行できるような形」は、[バイナリーコード](https://kotobank.jp/word/%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89-7251)になった実行ファイルである。


## 変数とメモリとアドレス
ポインタを理解するには、まず変数とメモリとアドレスの関係を理解する必要がある。
ここで整理したいと思う。

* メモリは、1バイト毎に番号がつけられ、区別されている
* 変数は実行ファイルになると、番号が割り当てられる
* 変数は、メモリ上の該当の番号の区分に格納され、記憶される
* この変数に付与されるメモリの区分番号をアドレスという

図にするとこんな感じ
![メモリと変数.png](https://qiita-image-store.s3.amazonaws.com/0/145611/0573f194-722f-68ab-2bb3-b5eef14da33d.png)

ここでいうメモリ1番地とかがアドレスで、実際にはあとで説明するが、`0x1040a0d0` みたいな感じの16進数で表される。


参考 : [変数とメモリの関係 - 苦しんで覚えるC言語](https://9cguide.appspot.com/15-02.html)

例えば、以下の様にする。

```go
name := "太郎"
```

そうすると、コンパイルした時に、メモリ上のある場所に変数の値が格納される。
この `メモリ上のある場所` が上記で説明した `アドレス` というものである。
メモリ上に変数が格納される場所がアドレスである。

実際に格納されたアドレスを16進数で表示させることもできる。
詳しくは[ここ](https://qiita.com/Sekky0905/items/c9cbda2498a685517ad0#%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF)を参照。


```go
package main

import "fmt"

// Person は人間を表す構造体。
type Person struct {
	Name string
	Age  int
}

func main() {
	// ポインタ型の変数を宣言する
	// pがポインタ変数
	// *Personポインタ型
	var p *Person

	p = &Person{
		Name: "太郎",
		Age:  20,
	}
	fmt.Printf("変数pに格納されているアドレス :%p", p)
}
```

実行結果

```
変数pに格納されているアドレス :0x1040a0d0
```


参考 : [メモリの仕組み - 苦しんで覚えるC言語](https://9cguide.appspot.com/15-01.html)


## ポインタPart

### ポインタ型とポインタ変数
ポインタという概念を学ぶ時に、よく以下のような説明を目にする。

* ポインタってのはメモリのアドレス情報のことだよ
* ポインタってのはアドレス情報を格納するための変数のことだよ

これらの説明はわかりやすいのだが、実際にコードを見た時には「結局どれがポインタなの?」ってなりがちだ。
その疑問ついて以下の記事が非常にわかりやすかったので、一読されるといいと思う。
[C言語のポインタきらい - Qiita](https://qiita.com/bugdasi/items/7856931f4cacf2c5b743#%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E5%9E%8B%E5%A4%89%E6%95%B0)

上記の記事によれば、以下のコードの pが `ポインタ変数` で、 `*Person` がポインタ型になる。

コード例

```go
package main

import "fmt"

// Person は人間を表す構造体。
type Person struct {
	Name string
	Age  int
}

func main() {
	// ポインタ型の変数を宣言する
	// pがポインタ型変数
	// *Personポインタ型
	var p *Person

	p = &Person{
		Name: "太郎",
		Age:  20,
	}
	fmt.Printf("p :%+v\n", p)
	fmt.Printf("変数pに格納されているアドレス :%p", p)
}

```

実行結果

```
p :&{Name:太郎 Age:20}
変数pに格納されているアドレス :0x1040a0d0
```
pを表示すると、 `&{Name:太郎 Age:20}` となることを覚えておいて欲しい。 
`&` については後ほど説明する。


ポインタ変数とは
> メモリ上のアドレスを値として入れられる変数のこと

引用元 : [ポインタ変数とは｜「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](http://wa3.i-3-i.info/word12814.html)

上記のコードでは、変数pがポインタ変数となり、実際にpにはアドレスが格納されている。(詳細は後述)

### デリファレンス
`&` を使うことで、ポインタ型を生成することができる。
Person型の変数pを `&p` とすると、Personへのポインタである `*Person型` の値を生み出すことができる。
`&p` は、pのアドレスという。

```go
package main

import "fmt"

// Person は人間を表す構造体。
type Person struct {
	Name string
	Age  int
}

func main() {

	// 値として、pに代入
	p := Person{
		Name: "太郎",
		Age:  20,
	}

	fmt.Printf("最初のp :%+v\n", p)

	p2 := p
	p2.Name = "二郎"
	p2.Age = 21
	// pではなく
	fmt.Printf("p2で二郎に書き換えを行なったはずのp :%+v\n", p)

	// &pで*Person(Personのポインタ型)を生成する
	// p3はpのアドレスが格納されている状態になる
	p3 := &p
	p3.Name = "二郎"
	p3.Age = 21

	fmt.Printf("p3で二郎に書き換えを行なったp :%+v\n", p)
}

```

実行結果

```
最初のp :{Name:太郎 Age:20}
p2で二郎に書き換えを行なったはずのp :{Name:太郎 Age:20}
p3で二郎に書き換えを行なったp :{Name:二郎 Age:21}
```

pはポインタではなく、Person型の値である。
`p2 := p` は、Person型の値コピーしてp2に格納しているので、p2で書き換えを行っても、それがpに反映されることはない。これを値渡しという。

逆に、`p3 := &p` は、*Person型(Personへのポインタである *Person型)をp3に格納しているので、p3はpのアドレス(Personへのポインタである *Person型)を持っていることになる。
従って、p3で書き換えを行うと、その変更はpに反映される。これを参照渡しという。

Goでは、構造体内のメソッド内で、構造体のフィールドの情報を変更するときには、この参照渡しをよく利用する。[ここ](https://qiita.com/y_ussie/items/ee520f9fe62d58d9610f)とかが参考になる。

## *Hoge型が格納された変数
`&` を使うことで、ポインタ型を生成することができた。
では、`&` を使って生成されたポインタ型を格納した変数はどう扱うか。
まずは、`&` の復習もかねて、以下のコードを見てみよう。

```go
package main

import "fmt"

func main() {
	name := "太郎"
	fmt.Printf("name :%v\n", name)

	namePoint := &name

	// namePointは、&nameが格納されているだけなので、stringへのポインタである *string型の値が格納されている。
	fmt.Printf("namePoint :%v\n", namePoint)

	// namePointが指している変数は、"*namePoint"という感じで、"*"をつけて表す。
	fmt.Printf("namePoint :%v\n", *namePoint)
}

```

実行結果

```
name :太郎
namePoint :0x1040c128
namePoint :太郎
```


コードに示したように `namePoint` には `&name` が格納されている。
`&` は、ポインタ型を生成するので`&name` は、stringへのポインタである `*string型` の値(アドレス)が格納されている。
よって、 `namePoint` を表示すると `*string型` の値である `name` のアドレスが格納されていることがわかる。

では、`namePoint` の元となっている `name` の変数に格納されている値(ここでは「太郎」)は、どのように取得すれば良いか。
そのような場合は、 `*namePoint` のように変数名の前に `*` をつければ良い。
なお、ここが紛らわしいところなのだが、 `*namePoint` 自体も変数なので、これに代入することもできる。
例えば、以下のようなコードだ。

```go
package main

import "fmt"

func main() {
	name := "太郎"
	fmt.Printf("name :%v\n", name)

	namePoint := &name

	// namePointは、&nameが格納されているだけなので、stringへのポインタである*string型の値が格納されている。
	fmt.Printf("namePoint :%v\n", namePoint)

	// namePointが指している変数は、"*namePoint"という感じで、"*"をつけて表す。
	fmt.Printf("namePoint :%v\n", *namePoint)

	*namePoint = "二郎"

	// *namePointに値を代入することもできる。
	fmt.Printf("*namePointに二郎を代入後の*namePoint :%v\n", *namePoint)

	// 再代入したところで、namePointに格納されている*string型の値(アドレス)自体は、変わらない
	fmt.Printf("*namePointに二郎を代入後のnamePoint :%v\n", namePoint)

	// stringへのポインタである*string型の値(nameに格納されている値)を書き換えたので、nameの値も変更される。
	fmt.Printf("*namePointに二郎を代入後のname :%v\n", name)
}

```

実行結果

```
name :太郎
namePoint :0x1040c128
namePoint :太郎
*namePointに二郎を代入後の*namePoint :二郎
*namePointに二郎を代入後のnamePoint :0x1040c128
*namePointに二郎を代入後のname :二郎
```

ここで注意すべきことは、
`*namePoint` に値を代入すると、nameの値も書き変わるということだ。
これはなぜか?
`*namePoint` には、 `&name` (stringへのポインタである*string型の値が格納されているからであり、それを `*namePoint = "二郎"` で書き換えているので、当然 `name` の値も書き変わるということである。

## まとめ
ポインタは確かにとっつきにくいかもしれないですが、Goを使用する上では必須ですし、使い方によっては非常に便利なものなので、ちゃんと理解して使っていきましょう。

## 参考
### 参考文献
松尾 愛賀　(2016/4/15)『スターティングGo言語』 翔泳社

Alan A.A. Donovan (著), Brian W. Kernighan (著), 柴田 芳樹 (翻訳)(2016/6/20)『プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)』丸善出版

### 参考にさせていただいたサイト
[バイナリーコード(ばいなりーこーど)とは - コトバンク](https://kotobank.jp/word/%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89-7251)

[変数とメモリの関係 - 苦しんで覚えるC言語](https://9cguide.appspot.com/15-02.html)

[メモリの仕組み - 苦しんで覚えるC言語](https://9cguide.appspot.com/15-01.html)

[C言語のポインタきらい - Qiita](https://qiita.com/bugdasi/items/7856931f4cacf2c5b743#%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E5%9E%8B%E5%A4%89%E6%95%B0)

[ポインタ変数とは｜「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](http://wa3.i-3-i.info/word12814.html)

[Part4 誰もがつまずくポインタを完璧理解 | 日経 xTECH（クロステック）](http://tech.nikkeibp.co.jp/it/article/COLUMN/20061206/256198/)

[C言語ポインタの基礎 - Qiita](https://qiita.com/lrf141/items/a3e96b315dd4f08508a9)

[Goのポインタ - はじめてのGo言語](http://cuto.unirita.co.jp/gostudy/post/pointer/)

[【C言語入門】ポインタのわかりやすい使い方(配列、関数、構造体) | 侍エンジニア塾ブログ | プログラミング入門者向け学習情報サイト](https://www.sejuku.net/blog/25094)

[もう一度基礎からC言語 第38回 プログラミングの周辺事項(1)～Cで書いたプログラムの仕組みと構造 Cプログラムの構造](https://www.grapecity.com/tools/support/powernews/column/clang/038/page03.htm)

[Go言語の構造体の値渡しとポインタ渡しの動作を確認してみる - Qiita](https://qiita.com/y_ussie/items/ee520f9fe62d58d9610f)