golang-基础-Go语言指针
Go 语言中的指针是编程中非常重要的概念,它允许直接操作内存地址,从而提高程序的效率和灵活性。
一、指针的基本概念
1. 什么是指针?
指针是一个变量,它存储了另一个变量的内存地址。通过指针,可以直接访问该内存地址上的数据。
2. 指针的操作符
&
:取地址运算符,用于获取变量的内存地址。*
:解引用运算符,用于根据地址访问该地址存储的值。
3. 指针的零值
Go 语言中,指针的零值是 nil
,表示指针不指向任何有效的内存地址。
二、指针的声明与使用
1. 声明指针
在 Go 语言中,指针的声明格式为:
var ptr *T
其中,T
是指针所指向的数据类型,ptr
是指针变量名。
示例代码
package main
import "fmt"
func main() {
var num int = 42
var ptr *int = &num // 声明一个指向 int 的指针
fmt.Println("Value of num:", num) // 输出: 42
fmt.Println("Address of num:", &num) // 输出: num 的地址
fmt.Println("Value of ptr:", ptr) // 输出: ptr 存储的地址
fmt.Println("Value pointed by ptr:", *ptr) // 输出: 42
}
三、指针的常见用法
1. 修改变量的值
通过指针可以修改变量的值,而无需返回修改后的值。
示例代码
package main
import "fmt"
func modifyValue(ptr *int) {
*ptr = 100 // 修改指针指向的值
}
func main() {
var num int = 50
fmt.Println("Before modification:", num) // 输出: 50
modifyValue(&num) // 传递 num 的地址
fmt.Println("After modification:", num) // 输出: 100
}
2. 结构体指针
结构体指针允许直接访问结构体字段,而无需解引用。
示例代码
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main() {
v := Vertex{1, 2} // 创建结构体实例
p := &v // 获取结构体指针
fmt.Println("Original values:", v) // 输出: {1 2}
p.X = 10 // 直接通过指针修改字段
p.Y = 20
fmt.Println("Modified values:", v) // 输出: {10 20}
}
四、数组与切片的指针
1. 数组指针
数组的指针指向数组的第一个元素的地址。
示例代码
package main
import "fmt"
func main() {
arr := [3]int{10, 20, 30}
ptr := &arr
fmt.Println("Array values:", arr) // 输出: [10 20 30]
fmt.Println("Array address:", &arr) // 输出: arr 的地址
fmt.Println("Pointer value:", ptr) // 输出: ptr 存储的地址
fmt.Println("First element via pointer:", (*ptr)[0]) // 输出: 10
}
2. 切片的指针
切片本身是一个指向底层数组的指针,因此对切片的修改会直接影响底层数组。
示例代码
package main
import "fmt"
func modifySlice(s []int) {
s[0] = 100 // 修改切片的第一个元素
}
func main() {
arr := []int{1, 2, 3}
fmt.Println("Before modification:", arr) // 输出: [1 2 3]
modifySlice(arr)
fmt.Println("After modification:", arr) // 输出: [100 2 3]
}
五、指针与函数参数传递
1. 值传递 vs 指针传递
Go 语言中,函数参数默认是值传递(即传递副本)。如果需要在函数内部修改外部变量的值,需要使用指针传递。
示例代码
package main
import "fmt"
func swap(x *int, y *int) {
*x, *y = *y, *x // 交换两个指针指向的值
}
func main() {
a, b := 100, 200
fmt.Println("Before swap:", a, b) // 输出: 100 200
swap(&a, &b)
fmt.Println("After swap:", a, b) // 输出: 200 100
}
六、多级指针
1. 什么是多级指针?
多级指针是指针的指针。例如,**int
是指向 *int
类型的指针。
示例代码
package main
import "fmt"
func main() {
a := 10
p := &a // *int 类型的指针
pp := &p // **int 类型的指针
fmt.Println("a:", a) // 输出: 10
fmt.Println("p:", p) // 输出: 0xc00001a078 (a 的地址)
fmt.Println("pp:", pp) // 输出: 0xc00000e018 (p 的地址)
fmt.Println("Value via pp:", **pp) // 输出: 10
**pp = 20 // 修改 a 的值
fmt.Println("a after modification:", a) // 输出: 20
}
2. 多级指针的使用场景
多级指针通常用于需要修改指针本身的场景,例如动态分配内存或修改指针指向的地址。
七、指针的注意事项
1. 空指针
空指针(nil
)不指向任何有效的内存地址。在使用指针前,必须确保它已经被正确初始化。
示例代码
package main
import "fmt"
func main() {
var ptr *int
if ptr == nil {
fmt.Println("Pointer is nil") // 输出: Pointer is nil
}
}
2. 野指针
野指针是指指向未知内存地址的指针。使用野指针可能导致未定义行为。
示例代码
package main
import "fmt"
func main() {
var ptr *int
*ptr = 10 // 错误!ptr 是 nil,导致运行时 panic
}
八、指针与结构体
1. 结构体指针的使用
通过结构体指针可以高效地操作结构体字段。
示例代码
package main
import "fmt"
type Rectangle struct {
Width, Height int
}
func (r *Rectangle) Area() int {
return r.Width * r.Height
}
func main() {
rect := &Rectangle{Width: 5, Height: 10}
fmt.Println("Area:", rect.Area()) // 输出: 50
}
九、指针与函数返回值
1. 返回指针
函数可以返回指针,以便调用者可以直接操作返回的值。
示例代码
package main
import "fmt"
func createValue() *int {
value := 42
return &value // 返回局部变量的地址(Go 语言中是安全的)
}
func main() {
ptr := createValue()
*ptr = 1010
fmt.Println("Value:", *ptr) // 输出: 1010
}
十、指针与性能优化
1. 传递大对象
当传递大型数据结构时,使用指针可以减少内存拷贝的开销。
示例代码
package main
import "fmt"
type LargeStruct struct {
Data [1000]int
}
func modifyByValue(s LargeStruct) {
s.Data[0] = 100
}
func modifyByPointer(s *LargeStruct) {
s.Data[0] = 100
}
func main() {
large := LargeStruct{}
fmt.Println("Before value call:", large.Data[0]) // 输出: 0
modifyByValue(large)
fmt.Println("After value call:", large.Data[0]) // 输出: 0(未修改)
modifyByPointer(&large)
fmt.Println("After pointer call:", large.Data[0]) // 输出: 100
}
十一、总结
概念 | 说明 |
---|---|
指针声明 | 使用 *T 声明指针类型 |
取地址符 | & 用于获取变量的内存地址 |
解引用符 | * 用于访问指针指向的值 |
空指针 | nil 表示指针不指向任何有效内存地址 |
多级指针 | **T 表示指向指针的指针 |
结构体指针 | 可以直接通过指针访问结构体字段 |
函数参数传递 | 使用指针传递可以在函数内部修改外部变量的值 |
通过合理使用指针,可以显著提高程序的性能和灵活性。但在使用时需要注意避免空指针和野指针问题,确保程序的安全性。
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 软件从业者Hort
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果