2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Goのポインタ変数

Last updated at Posted at 2019-09-07

ポインタ変数とは

メモリのアドレスを値として持つ変数のこと。

var intVal int      // int型の変数
var intPointer *int // intのポインタ変数

intVal = 5
intPointer = &intVal // intPointerはintValのアドレスを指し示す

fmt.Println(&intVal)     // 0x0000011
fmt.Println(intPointer)  // 0x0000011
fmt.Println(&intPointer) // 0x0000145

メモリは1Byte単位でアドレスがつけられて, そのアドレスで区別される。
上のコードの場合, intValはメモリを確保して5という値を直接格納する。
(下の図は64-bit環境基準でintは8bytesのため, アドレス8個分になっている)
intPointerはメモリを確保してintValのアドレスを値として格納する。

pointer.png

ポインタの扱い

ポインタ変数の定義

指し示す変数の型に合わせて*をつけて定義

var intPointer *int
var boolPointer *bool
var stringPointer *string

ポインタに参照先を設定する

nil状態のポインタの参照先に値をセットする場合, panicになる
(指してるところがないので, どこに値を入れればいいかわからない状態)

// int型のポインタ変数
var intPointer *int
*intPointer = 5 // panic: runtime error: invalid memory address or nil pointer dereference

変数のアドレスを代入する

一般的には変数のアドレスを代入して使う

var intPointer *int
intVal := 5

intPointer = &intVal

fmt.Println(intPointer)  // 0x0000011
fmt.Println(&intVal)     // 0x0000011

newでポインタに値をセット

変数を定義せずnewを利用して無名変数を代入することができる。

var intPointer *int
intPointer = new(int) // ゼロ値のint型がメモリに確保され, それを指し示すようになる
*intPointer = 5       // 指しているメモリアドレスに5をセットする

fmt.Println(*intPointer) // 5
fmt.Println(intPointer)  // 0xc000014080

参照先の値を変更

ポインタ変数名に*をつけると指し示す変数の扱いになる。

intVal := 5
intPointer := &intVal

fmt.Println(intVal)      // 5
fmt.Println(*intPointer) // 5

*intPointer = 10 // intVal = 10 するのと同じ

fmt.Println(intVal)      // 10
fmt.Println(*intPointer) // 10

ポインタ変数のサイズ

ポインタはメモリアドレスであるため, ポインタのサイズは指し示すデータのサイズではなく,
アドレスを指定できるメモリの最大量に基づいて決まる。
32-bitシステムでは4bytes(32bits), 64-bitシステムでは 8bytes(64bits)になる。

よって, 下記のように指し示すデータ型は異なってもポインタ変数のサイズは64-bitシステムでは全て8になる

type User struct {
	name  string
	birth time.Time
}

func main() {
	var intPointer *int
	var userPointer *User
	var boolPointer *bool

	fmt.Println(unsafe.Sizeof(intPointer))  // 8
	fmt.Println(unsafe.Sizeof(userPointer)) // 8
	fmt.Println(unsafe.Sizeof(boolPointer)) // 8
}

まとめ

スライスや構造体にはポインタがよく使われるのでGoで開発するにはポインタの理解は必要だ。
ポインタは何が値で何がアドレスか分かりにくくなるときがあるが, *&の書き方と意味をちゃんと理解しておけば, ポインタ演算がないGoでは案外難しくないかもしれない。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?