指针传递传递的是内存地址的副本还是指针的副本
在 Go 语言中,指针传递传递的是指针的副本,而这个指针本身是一个内存地址的值。所以更精确地说,传递的是内存地址的副本。
让我详细解释一下:
-
指针是什么?
- 在 Go 中,指针是一个变量,它存储的是另一个变量的内存地址。比如
var p *int,p是一个指针,指向某个整数的内存地址。 - 内存地址本身是一个值(通常是 64 位或 32 位整数,取决于系统架构)。
- 在 Go 中,指针是一个变量,它存储的是另一个变量的内存地址。比如
-
指针传递的过程
- 当你将一个指针传递给函数时,比如
func foo(p *int),Go 会将这个指针的值(即内存地址)复制一份,传递给函数。 - 函数接收到的
p是原始指针的副本,但这个副本仍然指向相同的内存地址。 - 因为是指向同一地址,函数可以通过解引用(
*p)修改原始值。
- 当你将一个指针传递给函数时,比如
-
为什么说是“内存地址的副本”?
- 传递的不是原始指针变量本身,而是它的值(内存地址)的副本。
- 这意味着函数内部如果修改了指针变量本身(比如让
p指向另一个地址),不会影响调用处的原始指针。但如果修改的是指针指向的内容(*p),则会影响原始值。
示例代码
package main
import "fmt"
func modifyPointer(p *int) {
fmt.Printf("函数内指针地址: %p\n", p) // p 是指针的副本
*p = 100 // 修改指针指向的内容
}
func reassignPointer(p *int) {
x := 200
p = &x // 修改 p 本身,让它指向新地址
}
func main() {
a := 10
fmt.Printf("原始指针地址: %p\n", &a)
modifyPointer(&a)
fmt.Println("修改后 a 的值:", a) // 输出 100
reassignPointer(&a)
fmt.Println("尝试重新赋值后 a 的值:", a) // 输出 100,未改变
}
输出解释
modifyPointer(&a):函数内的p是&a的副本,指向同一个地址,修改*p会改变a的值。reassignPointer(&a):函数内的p是副本,重新赋值p = &x只影响副本,不影响原始的&a,所以a不变。
结论
- 指针传递传递的是指针的副本,这个副本是一个内存地址的值。
- 函数内部可以通过这个地址修改原始数据,但如果修改指针本身(让它指向新地址),不会影响外部的原始指针。
我用一个通俗的比喻来解释 Go 中的值传递和指针传递,让你更容易理解。
比喻:寄快递
想象你有一本书,想要让朋友帮你修改这本书的内容。
-
值传递(Pass by Value)
- 你把整本书复印了一份,寄给了朋友(快递的是书的副本)。
- 朋友收到这本复印的书,在上面随便改,比如涂鸦、撕页,但你的原书一点没变,因为他改的是复印件。
- 特点:朋友拿到的是独立副本,改动不影响你的原书。复印整本书可能费时费力(如果书很厚,复制开销大)。
对应代码:
func modifyBook(book string) { book = "改了内容" } book := "原书" modifyBook(book) fmt.Println(book) // 还是 "原书" -
指针传递(Pass by Pointer)
- 你不寄整本书,而是写了一张纸条,上面写着“我的书在家里,地址是 XX 街 YY 号”,然后把这张纸条复印了一份寄给朋友。
- 朋友收到纸条副本,知道地址没变,顺着地址找到你的原书,直接在原书上改内容(比如加了几页笔记)。
- 你回家一看,书真的被改了,因为他操作的是原书。
- 特点:寄纸条很轻松(复制地址开销小),但朋友能直接改你的原书。纸条是副本,但指向的还是同一个地址。
对应代码:
func modifyBookByPointer(book *string) { *book = "改了内容" } book := "原书" modifyBookByPointer(&book) fmt.Println(book) // 输出 "改了内容" -
再加一个情况:朋友改了纸条上的地址
- 如果朋友收到纸条副本后,没去改你的书,而是把纸条上的地址改成他自己的书(比如“ZZ 街 WW 号”),然后在自己的书上改内容。
- 这时你的原书还是没变,因为他改的是他自己的书,纸条副本的指向变了,但不影响你手里的原纸条和原书。
对应代码:
func reassignPointer(book *string) { newBook := "新书" book = &newBook // 改了指针副本的指向 } book := "原书" reassignPointer(&book) fmt.Println(book) // 还是 "原书"
通俗总结
- 值传递:寄的是书的复印件,朋友怎么改都不影响你的原书。
- 指针传递:寄的是地址的复印件,朋友按地址找到原书,能直接改你的书。但如果朋友把地址改成别的,改的是他手里的纸条副本,不影响你的原书。

浙公网安备 33010602011771号