一、指针
1.1指针的概念
指针是存储另-个变量的内存地址的变量。
我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。
一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。
在上面的图中,变量b的值为156,存储在内存地址0x1040a124。
变量a持有b的地址,现在a被认为指向b。
1.2获取变量的地址
Go语言的取地址符是&,放到一个变量前使用就会返回相应变量的内存地址。
a := 10fmt.Println(\"a的数值:\", a) // 10fmt.Printf(\"a的类型:%T\\n\", a) // intfmt.Printf(\"a的地址:%p\\n\", &a) // 0xc0000160b0fmt.Println(\"a的地址:\", &a) // 0xc0000160b0
1.3声明指针
声明指针,*T是指针变量的类型,它指向T类型的值的内存地址。
p1 = &a
*p1 = a
通过 p1 就能去操作 变量a ,因为p1和a的地址都是一样的
指针的指针
var p2 **int
p2 = &p1
*p2 == p1
**p2 == a
a := 10fmt.Println(\"a的数值:\", a) // 10fmt.Printf(\"a的类型:%T\\n\", a) // intfmt.Printf(\"a的地址:%p\\n\", &a) // 0xc0000a0068fmt.Println(\"a的地址:\", &a) // 0xc0000a0068// 创建指针存储变量a的地址var p1 *intfmt.Println(p1) // <nil>p1 = &a // p1指向a的内存地址fmt.Println(\"a的地址\",p1) // 0xc0000a0068fmt.Println(\"p1的地址:\", &p1) // 0xc0000ca020fmt.Println(\"p1的数值是a的地址,该地址存储的数据(a的值):\", *p1) // 10fmt.Println(p1 == &a) // truefmt.Println(*p1 == a) // true*p1 = 200fmt.Println(a) // 200var p2 **intfmt.Println(p2)p2 = &p1fmt.Printf(\"%T, %T, %T\\n\",a,p1,p2) // int, *int, **intfmt.Println(p2 == &p1) // truefmt.Println(*p2 == p1) // truefmt.Println(**p2 == a) // true**p2 = 300fmt.Println(a) // 300
1.4 数组指针和指针数组
- 数组指针:首先是一个指针,存放一个数组的地址
- 指针数组:首先是一个数组,存储的数据类型是指针
*[5]float64, 指针,一个存储了5个浮点类型数据的数组的指针*[3]string, 指针,数组的指针,存储了3个字符串[3]*string, 数组,存储了5个浮点数据的地址的数组[5]*float64, 数组,存储了5个浮点数据的地址的数组*[5]*float64, 指针,存储了4个字符串数据的数组的指针的指针*[3]*string, 指针,存储了3个字符串的指针地址的数组的指针**[4]string, 指针,存储了4个字符串数据的数组的指针的指针**[4]*string, 指针,存储了4个字符串的指针地址的数组,的指针的指针
数组指针
arr1 := [4]int{1, 2, 3, 4}// 数组指针p3 := &arr1fmt.Printf(\"%T\\n\",p3) // *[4]intfmt.Println(*p3) // [1 2 3 4]fmt.Println(p3) // &[1 2 3 4]fmt.Println(&arr1) // &[1 2 3 4]fmt.Printf(\"%p\\n\",p3) // 0xc00009e1a0fmt.Printf(\"%p\\n\",&p3) // 0xc0000ca028(*p3)[0] = 100fmt.Println(*p3) // [100 2 3 4]fmt.Println(arr1) // [100 2 3 4]p3[0] = 200 // 简化写法fmt.Println(*p3) // [200 2 3 4]fmt.Println(arr1) // [200 2 3 4]
指针数组
// 指针数组b := 1c := 2d := 3arr2 := [3]int{b, c, d}arr3 := [3]*int{&b, &c, &d}fmt.Printf(\"%p, %p, %p\\n\",&b,&c,&d) // 0xc0000161d8, 0xc0000161e0, 0xc0000161e8// 数组是值传递fmt.Printf(\"%p, %p, %p\\n\",&arr2[0],&arr2[1],&arr2[2])// 0xc00000c600, 0xc00000c608, 0xc00000c610fmt.Println(arr2) // [1 2 3]fmt.Println(arr3) // [0xc0000161d8 0xc0000161e0 0xc0000161e8]fmt.Println(*arr3[0],*arr3[1],*arr3[2]) // 1 2 3
1.5 函数指针和指针函数
- 函数指针:一个指针,指向了一个函数的指针。因为go语言中,function, 默认看作一个指针,没有*。slice , map, function
- 指针函数:一个函数,该函数的返回值是一个指针。
指针函数
func main() {p4 := fun1()fmt.Println(p4) // &[1 2 3 4]fmt.Println(*p4) // [1 2 3 4]}func fun1() *[4]int {arr1 := [4]int{1,2,3,4}return &arr1}
1.6 指针作为参数
参数的传递:值传递、引用传递
func main() {num := 10fmt.Println(\"fun2()调用前,num的值\",num) // 10fun2(num)fmt.Println(\"fun2()调用后,num的值\",num) // 10fmt.Println(\"fun3()调用前,num的值\",num) // 10fun3(&num)fmt.Println(\"fun3()调用后,num的值\",num) // 100}func fun2(num int) {fmt.Println(\"fun2()函数中,num的值\",num) // 10num = 100fmt.Println(\"fun2()函数中修改,num的值\",num) // 100}func fun3(p *int) {fmt.Println(\"fun2()函数中,num的值\",*p) // 10*p = 100fmt.Println(\"fun2()函数中修改,num的值\",*p) // 100}