今川館

都内勤務の地味OLです

ポインタが分からない③

やっと分かってきた感

まだポインタのことで悩んでいたのかと言われても仕方ないが、以下の記事を読んでいてやっと分かってきた感じがする。

C/C++は永久に不滅です! - Part4 誰もがつまずくポインタを完璧理解:ITpro

この中の「図3●int *p =&a;を実行したときのメモリーの状態」という図を見て、気づいたことが、

p := 10
q := &p
*q = 7

これがコンパイルエラーにならないんじゃないかということ。
実際ならなくて、3行めの文によってqの大元の変数pに7という別の数を代入したことになる。
間接参照演算子「*」を左辺に持ってきてはいけないと思いこんでいたことに気づく。

サンプルコード

package main

import "fmt"

type Point struct {
	x int
	y int
}

func main() {
	p := Point{0, 0}
	q := &p
	r := *q // rにはqの大元の変数p(の値)を保持しておく。rとpは別のメモリが割り当てられる。

	fmt.Printf("p: %p q: %p  r:%p\n", &p, q, &r) // p: 0xc82000a320 q: 0xc82000a320  r:0xc82000a330

	p.x = 8
	fmt.Println(p, q, r) // {3 10} &{3 10} {0 0}

	// ここで、qの大元の変数に新しいPointのオブジェクトを入れる。
	// -> pに代入しているのと同じで、なおかつ、rには影響しない。
	*q = Point{3, 3} // 左辺に間接参照演算子「*」を持ってこられる点に驚き。

	p.y += 7

	fmt.Println(p, q, r) // {3 10} &{3 10} {0 0}
}

わかったこと

  1. 変数には、(普通の)変数とポインタ変数の2種類ある。
  2. 変数に変数を代入した場合は別々のメモリが割り振られる。 -> r = p としたら、pとrは別物。但し値がコピーされる。
  3. ポインタ変数を作って変数のアドレスを代入すると、同じものを指す。 -> q = &p としたら、pとqは同じもの。
  4. 間接参照演算子「*」を使うと、ポインタ変数の大元の変数にアクセスできる。これは参照も代入も可能。