Golang指针的基本概念
概念
指针的核心本质就是针对内存地址的操作。
在计算机科学中,内存被组织成一系列连续的存储单元,每个单元都有一个唯一的编号,这个编号就是内存地址。你可以把它想象成一条街上的门牌号,每个房子(内存单元)都有一个唯一的号码(地址)。
指针就是一个变量,其存储的值是另一个变量的内存地址。
不同语言的指针对比:
语言类别 | 指针概念 | 与内存地址的关系 |
---|---|---|
C/C++ | 裸指针 | 直接对应,可直接进行算术运算,非常底层和危险。 |
Pascal | 指针 | 类似C,但有更强的类型限制。 |
C#/Java | 引用 | 底层是指针,但对程序员完全抽象,无法直接操作地址,由虚拟机/运行时管理。 |
Go | 指针 | 支持指针运算,但不支持像C那样任意偏移,更安全。 |
Python/JS | 一切皆引用 | 所有变量名都是对对象的引用,语言完全隐藏了内存地址的细节。 |
Rust | 引用/裸指针 | 提供安全的引用(编译期检查)和不安全的裸指针,泾渭分明。 |
实例
package mainimport ("fmt"
)func changeValue(p int) {p = 10
}func main() {var a int = 1changeValue(a)fmt.Println("a = ", a)
}
输出:
go run firstGoProject.go
a = 1
这里参数的传递是值传递:将实际参数的一个副本传递给函数,函数内对参数的修改不会影响原始数据。
package mainimport ("fmt"
)func changeValue(p *int) { //*int p 声明了一个指向整数的指针变量 p。*p = 10 //*p 是解引用操作。它的意思是:“找到指针 p 所保存的地址,然后操作那个地址上的数据”。 //所以 *p = 10; 的意思是:找到地址 0x0843A040,然后把那里的值从 1 改为 10fmt.Println("p = ", p)
}func main() {var a int = 1changeValue(&a) //&a 是取地址操作,它得到的是变量 a 的地址,即 0x0843A040。fmt.Println("a = ", a)
}
输出:
go run firstGoProject.go
p = 0x0843A040
a = 10
解析
假设内存是一个公寓楼,声明变量a = 1 ——> a是公寓楼 0x0843A040号房间,住进了 “1” 的人。&a就是房间的门牌号 0x0843A040。声明(p *int)是房东记录的一张纸条上面写了a的门牌号。*p 表示房东拿着纸条找到a对应的房间看看里面住的人是谁(此时还是“1”)。*p = 10,“1” 房租到期了,房东把 0x0843A040号房间重新租给“10”。
输出p和&a都会输出a的内存地址(门牌号),*p输出是a的值(房子里住的人),*p = 10(把房间a住的人换成10)输出a会变成a=10。
表达式 | 中文读法 | 含义 |
---|---|---|
a | 变量 a | 变量 a 所存储的值 |
&a | a 的地址 | 变量 a 在内存中的地址 |
p | 指针 p | 指针 p 本身存储的值(它是一个地址) |
*p | 解引用 p | p 所指向的地址上存储的值(即变量 a 的值) |
&p | p 的地址 | 指针变量 p 自己在内存中的地址 |