Go 指针
指针保存的是另一个变量的内存地址。两个运算符:& 取地址,* 解引用(通过地址读写变量)。(说明:文中的片段代码需放进完整程序里运行)
取地址与解引用
完整示例:
package main
import "fmt"
func main() {
a := 10
p := &a // p 的类型是 *int,保存 a 的地址
fmt.Println(p) // 打印地址,每次运行数值不同
*p = 20 // 解引用:通过地址修改 a
fmt.Println(a) // 20
}
// 输出:
// 0xc0000120a0
// 20
&变量 得到指针,*指针 得到它指向的变量,两者互为逆操作。
空指针 nil
指针的零值是 nil(空指针)。对 nil 解引用会 panic,使用前要判空:
var p *int
fmt.Println(p == nil) // true
if p != nil { // 判空后再解引用
fmt.Println(*p)
}
a := 5
p = &a
fmt.Println(*p) // 5
指针参数:修改外部变量
普通参数按值传递,函数内改不动调用方的变量;传指针才能真正修改:
func swap(x, y *int) {
*x, *y = *y, *x // 交换两个指针指向的值
}
// a, b := 3, 8; swap(&a, &b) → a=8, b=3
指针数组
数组元素可以是指针类型,即每个元素都指向一个变量:
x, y := 1, 2
ptrs := [2]*int{&x, &y} // 指针数组:元素类型是 *int
*ptrs[1] = 20 // 通过下标取到指针,再解引用修改 y
fmt.Println(x, y) // 1 20
指向指针的指针(简述)
**int 是指向 *int 的指针,两层解引用才拿到最终变量,只在需要修改指针本身的场景使用:
a := 10
p := &a // *int
pp := &p // **int
fmt.Println(**pp) // 10
与 C 语言的差异
- Go 指针不能做算术运算:
p++、p+1非法(C 允许)。 - Go 有垃圾回收,无需手动
free,没有悬垂指针崩溃问题。 - 可以对局部变量取地址,编译器通过逃逸分析安全处理。
- 指针类型不能随意转换,比 C 的强转安全得多。
小结:Go 指针比 C 安全——不能运算、有 GC 兜底。记住 & 取地址、* 解引用、先判空再用即可。