【Go语言基础【12】】指针:声明、取地址、解引用
文章目录
- 零、概述:指针 vs. 引用(类比其他语言)
- 一、指针基础概念
- 二、指针声明与初始化
- 三、指针操作符
- 1. `&`:取地址(拿到内存地址)
- 2. `*`:解引用(拿到值)
- 四、空指针(nil)
- 五、指针作为函数参数
- 六、多维指针(指针的指针)
- 七、指针与切片/Map的关系
- 1. 切片(slice)
- 2. Map(make初始化)
- 八、注意事项
- 1. 禁止指针运算
- 2. 避免空指针解引用
- 3. 指针与值类型的选择
零、概述:指针 vs. 引用(类比其他语言)
特性 | 指针(Go) | 引用(C++) |
---|---|---|
本质 | 存储地址的变量 | 变量的别名(无独立地址) |
空值 | 支持nil | 必须指向有效变量 |
操作符 | & 取地址,* 解引用 | & 声明引用,直接操作 |
可变性 | 可重新指向其他变量 | 初始化后不可更改指向 |
一、指针基础概念
Go语言中的指针(Pointer)用于存储变量的内存地址,是实现高效数据操作的重要工具。与C语言相比,Go指针具有以下特点:
- 安全性:不支持指针运算(如指针加减整数),避免非法内存访问。
- 简化性:通过
&
取地址、*
解引用,语法简洁。 - 空指针:默认值为
nil
,避免野指针问题。
指针与变量的关系
- 变量:存储数据值,占据内存空间,可通过
&
获取地址。a := 10 // 变量a存储值10 addr := &a // addr存储a的地址(如0xc00001a0b8)
- 指针:专门存储地址的变量,类型为
*T
(T
为目标数据类型)。var ptr *int // 声明指向int的指针 ptr = &a // 指针ptr指向变量a的地址
二、指针声明与初始化
1. 声明指针变量
var ptr *int // 指向int的指针
var strPtr *string // 指向string的指针
var arrPtr *[5]int // 指向数组的指针2. 初始化为空指针var nilPtr *int // 初始值为nil(空指针)
fmt.Println(nilPtr == nil) // true3. 使用`new`函数初始化
`new(T)` 用于分配类型为`T`的零值内存,返回`*T`类型指针。 ptr := new(int) // 分配int类型内存,值为0
*ptr = 20 // 通过解引用赋值
fmt.Println(*ptr) // 输出:204. 直接赋值初始化a := 10
ptr := &a // 指针直接指向已有变量的地址
三、指针操作符
1. &
:取地址(拿到内存地址)
获取变量的内存地址,返回对应类型的指针。
a := "hello"
addr := &a // addr类型为*string,存储a的地址
*addr += "1212"
fmt.Println(*addr)hello1212
2. *
:解引用(拿到值)
通过指针获取目标变量的值,或修改目标变量的值。
ptr := new(int) // ptr类型为*int,指向值为0的int
*ptr = 100 // 通过解引用修改值
fmt.Println(*ptr) // 输出:100
四、空指针(nil)
- 定义:未指向任何有效内存的指针,默认值为
nil
。 - 作用:避免野指针,明确表示指针未初始化。
- 判断:
var ptr *int if ptr == nil {fmt.Println("指针未初始化") // 会执行 }
五、指针作为函数参数
通过指针传递参数,可在函数内部修改原始变量的值(避免值传递的拷贝开销)。
func modify(ptr *int) {*ptr = 200 // 通过解引用修改指针指向的值
}func main() {a := 100modify(&a) // 传递a的地址fmt.Println(a) // 输出:200(原始变量已修改)
}
六、多维指针(指针的指针)
指针的指针用于存储指针变量的地址,语法为**T
(二维指针)、***T
(三维指针)等。
func main() {a := 10 // 变量aptr1 := &a // 一维指针:*int,指向aptr2 := &ptr1 // 二维指针:**int,指向ptr1ptr3 := &ptr2 // 三维指针:***int,指向ptr2// 通过多维指针修改原始值**ptr2 = 20 // 等价于*ptr1 = 20,即a = 20***ptr3 = 30 // 等价于**ptr2 = 30,即*ptr1 = 30,a = 30fmt.Println(a) // 输出:30
}
七、指针与切片/Map的关系
1. 切片(slice)
切片本身是引用类型,其底层结构体包含指针,指向底层数组。
s := []int{1, 2, 3}
ptr := &s // ptr类型为*[]int,指向切片本身(非底层数组)
fmt.Println(ptr)//&[1 2 3]
2. Map(make初始化)
Map也是引用类型,声明后需通过make
初始化,指针操作与切片类似。
m := make(map[string]int)
ptr := &m // ptr类型为*map[string]int
八、注意事项
1. 禁止指针运算
Go不支持指针加减整数、指针比较大小等操作(避免内存越界)。
ptr := new(int)
ptr++ // 编译错误:invalid operation: ptr++ (non-numeric type *int)
2. 避免空指针解引用
对nil
指针执行解引用会导致运行时恐慌(panic)。
var ptr *int // nil指针
fmt.Println(*ptr) // panic: runtime error: invalid memory address or nil pointer dereference
3. 指针与值类型的选择
- 值类型(如
int
、struct
):默认值传递,修改需用指针。 - 引用类型(如切片、map、通道):本身包含指针,传递时无需额外取地址。