📌Golang📌基础📌J-pointer指针.txt
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。
当一个指针被定义后没有分配到任何变量时,它的值为nil,没有NULL常量。
操作符"&"(取地址符)取变量地址,"*"(取值符)透过指针访问目标对象。
Golang支持指针类型*T,指针的指针**T,以及包含包名前缀的*.T。

指针声明格式如下:
	var name *类型
例如:
	var ip *int     // 指向整型,声明一个int值得指针变量
	var sp *string  // 指向字符串类型

返回局部变量指针是安全的,编译器会根据需要将其分配在GC Heap上。
	x := 100
	return &x // 在堆上分配x内存。但在内联时,也可能直接分配在目标栈。

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。
当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:
指向指针的指针变量声明格式如下:
	var ptr **int
以上指向指针的指针变量为整型。
访问指向指针的指针变量值需要使用两个*号
	var a int
	var ptr *int
	var pptr **int
	a = 3000
	ptr = &a    // 指针ptr地址
	pptr = &ptr // 指向指针ptr地址
	fmt.Printf("变量 a = %d\n", a) // 变量 a = 3000
	fmt.Printf("指针变量 *ptr = %d\n", *ptr) // 指针变量 *ptr = 3000
	fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr) // 指向指针的指针变量 **pptr = 3000

可以在unsafe.Pointer和任意类型指针间进转换。
	x := 0x12345678
	p := unsafe.Pointer(&x) // *int -> Pointer
	n := (*[4]byte)(p)      // Pointer -> *[4]byte
	for i := 0; i < len(n); i++ {
		fmt.Printf("%X ", n[i]) // 78 56 34 12 
	}

将Pointer转换成uintptr,可变相实现指针运算。
	d := struct {
		s string
		x int
	}{"abc", 100}
	p := uintptr(unsafe.Pointer(&d)) // *struct -> Pointer -> uintptr
	p += unsafe.Offsetof(d.x)        // uintptr + offset
	p2 := unsafe.Pointer(p) // uintptr -> Pointer
	px := (*int)(p2)        // Pointer -> *int
	*px = 200               // d.x = 200
	fmt.Printf("%#v\n", d) // struct { s string; x int }{s:"abc", x:200}
GC把uintptr当成普通整数对象,它无法阻止"关联"对象被回收。

unsafe.Pointer是一种特殊意义的指针,它可以包含任意类型的地址,有点类似于C语言里的void*指针,全能型的。
	i := 10
	ip := &i
	var fp *float64 = (*float64)(unsafe.Pointer(ip))
	*fp = *fp * 3
	fmt.Println(i) // 30

unsafe.Pointer的4个规则。
任何指针都可以转换为unsafe.Pointer
unsafe.Pointer可以转换为任何指针
uintptr可以转换为unsafe.Pointer
unsafe.Pointer可以转换为uintptr

unsafe是不安全的,所以应该尽可能少的使用它,比如内存的操纵,这是绕过Go本身设计的安全机制的,不当的操作,可能会破坏一块内存,而且这种问题非常不好定位。