「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。
概念
- 指针是存储另一个变量的内存地址的变量
- 变量是一种使用方便的占位符,用于引用计算机内存地址
- 指针保存了值的内存地址,指针可以指向任何一个值的内存地址
- 变量 b 的值为156,存储在内存地址 0x1040a124
- 变量 a 保存 b 的地址,现在 a 指向 b
为什么说 Go 指针简单?
因为指针不能运算,而 C 语言的指针可以运算
语法格式
var v *T
类型*T是指向 T 类型值的指针,其零值为 nil
声明指针的🌰
var v *int
var s *string
& 操作符
&操作符会生成一个指向其操作数的指针,其实就是返回变量的内存地址
package main
import "fmt"
func main() {
var a int = 10
fmt.Printf("变量的地址: %x\n", &a )
}
运行结果
变量的地址: c000018030
* 操作符
*操作符表示指针指向的底层的值,就是获取指针指向的变量的值
package main
import "fmt"
func main() {
var a int = 10
b := &a
fmt.Printf("变量的地址: %x \nb 指针的值:%v\n", &a, *b)
}
运行结果
变量的地址: c00009c000
b 指针的值:10
指针的综合🌰
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // 指向 i
fmt.Printf("type %T, value %v ,address %v, i-address %v \n", p, *p, p, &i) // 通过指针读取 i 的值,并且查看他们的内存地址
*p = 222 // 通过指针设置 i 的值
fmt.Println(i) // 查看 i 的值
p = &j // 重新指向 j
fmt.Printf("type %T, value %v ,address %v, j-address %v \n", p, *p, p, &j) // 通过指针读取 j 的值,并且查看他们的内存地址
*p = *p / 37 // 通过指针对 j 进行除法运算
fmt.Println(j) // 查看 j 的值
}
运行结果
type *int, value 42 ,address 0xc000018030, i-address 0xc000018030
222
type *int, value 2701 ,address 0xc000018038, j-address 0xc000018038
73
同一个指针变量可以指向不同的值的内存地址
空指针
- 当一个指针被定义后没有分配到任何变量时,它的值为 nil
- nil 指针也称为空指针
- nil 在概念上和其它语言的 null、None、nil、NULL 一样,都指代零值或空值
- 一个指针变量通常缩写为 ptr
package main
import "fmt"
func main() {
var a *int
fmt.Printf("type %T, value %v", a, a)
}
运行结果
type *int, value <nil>
Go 语言使用值传递?引用传递?
Go 语言只有值传递一种方式
值传递
package main
import "fmt"
func f(a int){
a = 3
}
func main() {
var a int = 0
f(a)
fmt.Println(a)
}
运行结果
0
值传递的原理
拷贝变量 a 到参数 a,它们的内存地址是不一致的
指针传递
package main
import "fmt"
func f(pa *int){
*pa = 3
}
func main() {
var a int = 0
// 传递的是指针
f(&a)
fmt.Println(a)
}
运行结果
3
指针传递的原理
- 实际上也是值传递
- 只不过是拷贝了 &a 给 pa,就是将 a 的内存地址拷贝给了 pa
- 所以 pa 指针保存的也是变量 a 的内存地址
- 当修改 pa 的时候,也会同步修改 a 的值
- 总结: Go 没有引用传递,只是通过指针传递实现了引用传递
两个变量交换值
这应该是经典案例了
通过值传递完成
通过 Go 函数可以返回多个值的特性来完成
package main
import "fmt"
func swapByValue(a, b int) (int, int) {
a, b = b, a
return a, b
}
func main() {
a, b := 11, 22
fmt.Println(a, b)
a, b = swapByValue(a, b)
fmt.Println(a, b)
}
运行结果
11 22
22 11
通过指针传递来完成
package main
import "fmt"
func swapByPointer(a, b *int) {
*a, *b = *b, *a
}
func main() {
a, b := 11, 22
fmt.Println(a, b)
swapByPointer(&a, &b)
fmt.Println(a, b)
}
运行结果
11 22
22 11