为什么需要指针
首先有一段代码:
package main
import "fmt"
func changeValue(p int){
p = 10 // 尝试修改传递过来的参数的值
}
func main (){
var a int = 1
changeValue(a) // 将a作为实参传入函数
fmt.Println("a = ", a) // 请问打印出的是多少
}
分析:
第10行新建变量a 这个变量,变量值为1
- 此时在内存中开辟了一个内存地址1,用来存放a这个变量的值:1
第11行当调用函数
changeValue
时- 首先创建形参p,分配一个内存地址2,用来存放形参p的初始化默认值:0
- 接着将实参a的值传递给形参p的内存地址2,替换掉默认值0,此时内存地址2存放的值为1
- 接着指定到第6行函数体内部,修改形参p的值为10,也就是将内存地址2中的值从1修改成10
- 第12行打印a的值,即内存地址1的值,因为内存地址1没有做任何改动,所以仍为1
这就是相当于值的传递,不是传递a的内存地址,而是仅仅传递了a的内存的值。
运行的结果:
指针的作用
现在想要修改函数体中的形参p达到修改变量a的值,这个时候就要使用到指针了
代码修改成以下:
package main
import "fmt"
func changeValue2(p *int){ // 现在的p表示指针类型的一个变量
*p = 10 // *p表示p指向的内存地址存储的值
}
func main (){
var a int = 1
changeValue2(&a) // 表示传递的为a的内存地址
fmt.Println("a = ", a)
}
分析:
第10行新建变量a 这个变量,变量值为1(与之前一样)
- 此时在内存中开辟了一个内存地址1,用来存放a这个变量的值:1
第11行当调用函数
changeValue
时- 首先形参
p *int
,为指针类型的一个变量,分配一个内存地址2,内存地址初始化值也为0,但不是0这个值而是为0地址 - 将
&a
传递给p,也就是说将现在 p *int的内存地址2存储的0地址修改成a变量的内存地址,所以现在的变量p内存存储的值为变量a的内存地址,也称为指针p指向a,p存的值为a的内存地址,所以通过P就能找到a。
- 首先形参
- 第6行p代表p的内存存储的值,p表示p存储的内存地址所代表的变量的内存,p=10表示通过p存储的值(这个值为一个内存地址),找到存储的内存地址(也就是a的地址1)指向的内存(也就是a的值)修改成10
- 第12行打印a的值为10
运行结果:
指针经典案例:交换两个值
package main
import "fmt"
func swap(pa *int, pb *int) {
var tmp int
tmp = *pa // tmp = main函数中的a
*pa = *pb // main中的a = main中的b
*pb = tmp // main中的b = tmp
}
func main() {
var a int = 10
var b int = 1
swap(&a, &b)
fmt.Println("a = ", a," b = ", b)
}
运行结果:
成功交换。
二级指针
一般指针在go中就比较少见,二级指针更是少见。
二级指针案例:
func main() {
var a int = 10
var b int = 1
swap(&a, &b)
fmt.Println("a = ", a," b = ", b)
var p *int
p = &a
fmt.Println("&a = ", &a)
fmt.Println("&b = ", p)
var pp **int // 二级指针
pp = &p
fmt.Println("pp = ", pp)
fmt.Println("&p = ", &p)
}
运行结果:
总结
- 如果希望函数可以修改函数以外的变量的值,可以使用指针
此处评论已关闭