指针和引用是什么

答:指针和引用可以用洋葱来举例

 先声明并赋值变量A,
 再声明一个指向A的指针变量Z1
 再声明一个指向Z1的指针变量Z2
 再声明一个指向Z2的指针变量Z3
 
 变量的左边, 加一个&引用符号 , 就像加了一层洋葱皮	
 如果加多个&符号,就像加了多层皮 
 要剥开层层洋葱皮, 就必须在左侧加 *, 直到看到对象本身数据
 
 例如:如果想通过Z3访问A 就要根据&引用嵌套层数, 加*展开 (***Z3)
	A := "hello"
	Z1 := &A
	Z2 := &Z1
	Z3 := &Z2
	fmt.Println(A,Z1, Z2, Z3, *Z3, **Z3, ***Z3)
// hello 0xc00004a3a0 0xc000006060 0xc000006068 0xc000006060 0xc00004a3a0 hello
go语言与c 语言

go是为了兼容c和c++, 并简化c的一种语言
go比java 复杂,例如:保留了指针概念,
但是比c++更高效和安全

go与c指针有啥不同

本质是一样的,用法也差不多, 但是也有改进之处

go与c 的指针结构示意

引用值
指针 1地址
go比c的引用更直观

“c语言” 在输出结构体变量的引用结果时, 显示变量的地址
“go语言” 在输出结构体变量的引用结果时, 会显示成 “&变量”,而不是变量的地址
因为本质并没有改变,所以我认为它这么设计的原因只是为了方便调试

为了更好理解可以用以下代码调试
import "fmt"

type Tt1 struct {
	ss string
}


func p1() Tt1 {
	var t1 Tt1

	t1 = Tt1{
		"dfsg",
	}
	fmt.Println("1.1", t1, &t1)

	t2 := t1
	fmt.Println("1.2", t2, &t2)
	//	var t3 *Tt1
	t3 := &t1
	fmt.Println("1.3", t3, &t3, *t3)

	t4 := t3
	fmt.Println("1.4", t4, &t4, *t4)

	t5 := &t3
	fmt.Println("1.5", t5, &t5, *t5, **t5)

	t7 := unsafe.Pointer(&t1)
	fmt.Println("1.7", t7, &t7)

	return t1

}
func p2() *Tt1 {

	//var t1 *Tt1

	t1 := &Tt1{
		"dfsg",
	}
	fmt.Println("2.1", t1, &t1, *t1)

	return t1

}
func p3() {
	//普通变量
	d1 := "sdfasf"
	fmt.Println("3.1", d1, &d1)

	d2 := 123
	fmt.Println("3.2", d2, &d2)

	// 非普通变量

	d3 := [4]byte{1, 3, 4}
	fmt.Println("3.3", d3, &d3)

	d4 := []byte{1, 3, 4}
	fmt.Println("3.4", d4, &d4)

}

func p4() {
	A := "hello"
	Z1 := &A
	Z2 := &Z1
	Z3 := &Z2
	fmt.Println("4.1", A,Z1, Z2, Z3, *Z3, **Z3, ***Z3)

}


func main() {

	t1 := p1()
	fmt.Println("1", t1, &t1)

	t2 := p2()
	fmt.Println("2", t2, &t2)

	p3()
	
	p4()
}
输出结果是
1.1 {dfsg} &{dfsg}
1.2 {dfsg} &{dfsg}
1.3 &{dfsg} 0xc000096558 {dfsg}
1.4 &{dfsg} 0xc000096560 {dfsg}
1.5 0xc000096558 0xc000096568 &{dfsg} {dfsg}
1.7 0xc0000a7020 0xc000096570
1 {dfsg} &{dfsg}
2.1 &{dfsg} 0xc000096580 {dfsg}
2 &{dfsg} 0xc000096578
3.1 sdfasf 0xc0000a7140
3.2 123 0xc000086480
3.3 [1 3 4 0] &[1 3 4 0]
3.4 [1 3 4] &[1 3 4]
4.1 hello 0xc00004a3a0 0xc000006060 0xc000006068 0xc000006060 0xc00004a3a0 hello