十三、指针
相比于c或c++,go语言的指针是很容易学习的,它可以更简单地执行一些任务。
1 取地址操作符&
变量是一种使用方便的占位符,用于引用计算机内存地址,使用&
符号获取变量的内存地址,如下:
func main() {
var str = "hello world"
fmt.Println(&str)
// 返回结果为0xc00004c230
}
2 指针的定义
指针是一个变量,这个变量存储了另一个变量的内存地址。
在使用指针前,你需要声明指针。指针声明格式如下
var var_name *var-type
// var_name 为指针变量名
// var-type 为指针类型
举例:
var ptr1 *string // 指向字符串
var ptr2 *int // 指向整型
当一个指针被定义后没有分配到任何变量时,它的初始值为nil,也被称为空指针
func main() {
var ptr *int
fmt.Println(ptr) // 未分配的指针初值为<nil>
fmt.Println(&ptr) // 指针作为一个变量,也可以取到它的内存地址
fmt.Println(*ptr) // 未分配的指针,获取指针指向的内容时会报错panic: runtime error: invalid memory address or nil pointer dereference
}
3 使用指针
定义指针后,需要给指针变量赋值,使用*
操作符可以获取指针指向的内容(也称解引用)。
func main() {
var ptr *int // 声明指针变量,它指向一个整型变量,初始化一个空指针
b := 3 // 创建变量b为整型变量
ptr = &b // 将变量b的内存地址赋值给指针,也称'指针ptr指向了b'
fmt.Println(ptr)
fmt.Println(b)
fmt.Println(*ptr) // 指针解引用,获取指针所指向的变量的值
}
4 指针的函数传递
指针也是一个变量,可以向函数传递。
func add(ptr *int) {
*ptr++
}
func main() {
a := 10
var ptr *int = &a
add(ptr)
print(a)
}
5 指针运算
与c和c++不同,go中的指针不支持对指针运算,比如指针的递增和递减。
a := 10
var ptr *int = &a
ptr++ // 不支持指针运算,返回错误invalid operation: ptr++ (non-numeric type *int)
6 多级指针
已知指针本身也是变量,指针存放的是变量的内存地址。所以,可以让一个指针存放另一个指针变量的地址,此时称这个指针变量为指向指针的指针(二级指针)。
a := 10
var ptr *int = &a
var pptr **int
pptr = &ptr
fmt.Println(a) // 10
fmt.Println(ptr) // 0xc0000160b8
fmt.Println(pptr) // 0xc000006028
fmt.Println(*pptr) // 0xc0000160b8
fmt.Println(**pptr) // 10
如上面的例子,二级指针解引用时,需要使用两个*
同理,你可以“无限套娃”下去,定义多级指针。
下面是一个三级指针、四级指针的例子:
a := 10
var ptr *int = &a
var pptr **int
var ppptr ***int
var pppptr ****int
pptr = &ptr
ppptr = &pptr
pppptr = &ppptr
fmt.Println(a)
fmt.Println(ptr)
fmt.Println(pptr)
fmt.Println(ppptr)
fmt.Println(pppptr)