一、内存地址
在了解指针之前,我们需要先知道什么是内存地址。先看下面的代码,我们定义var i int = 10的变量
package main
import "fmt"
func main(){
var i int = 10
fmt.Println(i)
}
在我们定义变量的时候,他会在内存空间分配一块区域,来存放我们的值
但是这个内存空间 本身也是有一个地址的,那么我们怎么拿到这个内存地址呢 "&"
获取变量的内存地址
package main
import "fmt"
func main(){
var i int = 10
fmt.Println("i的内存地址=",&i) //通过在变量前面设置&
//在这样就可以把变量i的内存地址取出来
}
返回
i的内存地址= 0xc00000a098
也就是说上面变量i 指定的内存地址 如下
二、指针
指针类型存放的是内存地址,通过指定内存空间来获取对应的值
想要定义一个指针的数据类型,只需要在基本数据类型前面加星号(*) 即可 如 *int
案例
package main
import "fmt"
func main(){
var i int = 10
fmt.Println(&i)
var ptr *int //这里定义了一个int类型的指针
ptr = &i //指针只能存放内存地址,通过前面的&号将变量i的内存地址赋值给指针变量ptr
fmt.Printf("Ptr=%v\n",ptr) //直接输出ptr的话,我们只能得到指针变量里面存放的值,也就是变量i的内存地址
fmt.Printf("Ptr=%v\n",*ptr) //如果想要输出存放的内存地址的值,要在变量前面加星号(*)
}
返回
0xc00000a098
Ptr=0xc00000a098
Ptr=10
我们可以看到,指针变量ptr的值,存放的就是变量i的内存地址。也就是说在ptr指向了变量i的内存地址
说明
上面我们通过 &i 得到了i变量的内存空间的地址是0xc00000a098,ptr的变量的值实际上是i变量的内存空间的值,
如图所知,既然i变量的值是10,内存空间是0xc00000a098,ptr变量的值是0xc00000a098,ptr也是一个变量
那么ptr变量所存放值的地方,是不是也会有一个内存空间呢?是的,ptr这个指针变量也会指向一个内存空间
案例
package main
import "fmt"
func main(){
var i int = 10
fmt.Println("i的地址=",&i)
var ptr *int = &i
fmt.Printf("Ptr=%v\n",ptr)
//同样的道理,他也可以用地址符去取
fmt.Printf("ptr 指针变量的内存地址=%v",&ptr)
}
返回
i的地址= 0xc00000a098
Ptr=0xc00000a098
ptr 指针变量的内存地址=0xc0000ce020
我们再套个娃,这里去获取指针变量ptr的值
package main
import "fmt"
func main(){
var i int = 10
fmt.Println("i的地址=",&i)
var ptr *int = &i
fmt.Printf("Ptr存储内存地址的值=%v\n",ptr) //输出ptr指针变量的值 变量i的内存地址
fmt.Printf("ptr存储内存地址指向的值=%v\n",*ptr) //获取ptr的值
fmt.Printf("ptr自身指针变量的内存地址=%v\n",&ptr) //同样的道理,他也可以用地址符去取,输出ptr的内存地址
fmt.Printf("变量i的值=%v\n",**&ptr)
//通过调用ptr指针变量内存地址(&ptr),去调用ptr指针变量存储值(*ptr),
//上面获取的还是内存地址,所以要再一次*获取真正的值所以是**&ptr
//每多一层指针,调用加一层*
}
小练习
1、写一个程序,获取一个变量num的地址,并显示到终端
2.、将num的地址赋给指针ptr,并通过ptr去修改num的值
package main
import "fmt"
func main() {
num := 10
fmt.Println(&num)
var ptr *int = &num
fmt.Println(*ptr)
fmt.Println(ptr)
*ptr = 20 //修改指针变量指定的内存空间的值, 基于地址的修改会影响原先的值
fmt.Println(num) //查看原始值
fmt.Println(*ptr) //查看指针变量指定的内存空间的值
}
错误案例
var ptr *int = a //错误,指针变量是要接收一个内存地址的。这里给了一个值,所以会出错
var ptr *float32 = &a //错误 指针的类型必须要和接收的地址的类型必须相同
练习2
package main
import "fmt"
func main(){
var a int = 300
var b int = 400
var ptr *int
ptr = &a
*ptr = 100
ptr = &b
*ptr = 200
fmt.Printf("a=%d,b=%d,ptr=%d",a,b,*ptr)
}
//猜猜以上代码会输出什么
//100,200,200
指针细节说明
1. 值类型,都有对应的指针类型,形式为 *数据类型
比如int的对应的指针就是*int, float32对应的指针类型就是 *float32,以此类推
2. 值类型包括
基本数据类型int系列
float系列
bool
string
数组
结构体
三 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil, nil 指针也称为空指针
nil 在概念上和其它语言的 null 、 None 、 nil 、 NULL 一样,都指代零值或空值 、空指针值为 nil,即没有内存地
案例
package main
import "fmt"
func main(){
var intP *int
fmt.Println(*intP)
}
返回
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0xa7c516]
这时候该怎么办呢?其实只需要通过 new 函数给它分配一块内存就可以了,如下
package main
import "fmt"
func main(){
var intP *int = new(int) //new(int) 分配一块内存空间,数据类型是int
fmt.Println(*intP) //0
}
案例 空指针输出
package main
import "fmt"
func main() {
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr )
//或者进行判空操作
if(ptr != nil){
fmt.Println("内存地址为",ptr)
}else {
fmt.Println("ptr 为空指针")
}
}