指针类型
1.1、指针的基本使用
计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用 4 个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。
我们将内存中字节的编号称为地址(Address)或指针(Pointer)。地址从 0 开始依次增加,对于 32 位环境,程序能够使用的内存为 4GB,最小的地址为 0,最大的地址为 0XFFFFFFFF。
数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量。
Go语言中使用对于指针存在两种操作: 取址
和取值
。
| 符号 | 名称 | 作用 |
| :-------- | :----- | :--------------------- |
| &变量 | 取址符 | 返回变量所在的地址 |
| *指针变量 | 取值符 | 返回指针指地址存储的值 |
var x = 100
// 取址符:& 取值符:*
fmt.Println("x的地址:", &x)
// 将地址值赋值给的变量称为指针变量
var p *int
p = &x
fmt.Println("p的值:", p)
fmt.Println("p地址对应的值", *p)
关于地址的格式化打印
var x = 10
fmt.Printf("%p\n", &x)
x = 100
fmt.Printf("%p\n", &x)
fmt.Println(*&x)
关于指针的应用:
// 当使用等号将一个变量的值赋给另一个变量时,如 x = y ,实际上是在内存中将 i 的值进行了拷贝
var x = 10
var y = x
var z = &x
x = 20
fmt.Println(y)
fmt.Println(*z)
*z = 30
fmt.Println(x)
练习1
var x = 10
var y = &x
var z = *y
x = 20
fmt.Println(x)
fmt.Println(*y)
fmt.Println(z)
练习2
var a = 100
var b = &a
var c = &b
**c = 200
fmt.Println(a)
提示
- Go语言的指针类型变量即拥有指针高效访问的特点,又不会发生指针偏移和运算,从而避免了非法修改关键性数据的问题。
1.2、new函数
new 和 make 是 Go 语言中用于内存分配的原语。简单来说,new 只分配内存,make 用于初始化 slice、map 和 channel。
之前我们学习的基本数据类型声明之后是有一个默认零值的,但是指针类型呢?
var p *int
// fmt.Println(p) // <nil>
// fmt.Println(*p) // 报错,并没有开辟空间地址
*p = 10. // 报错
我们可以看到初始化⼀个指针变量,其值为nil,nil的值是不能直接赋值的。通过内建的new函数返回⼀个指向新分配的类型为int的指针,指针值为0xc00004c088,这个指针指向的内容的值为零(zero value)。
var p *int = new(int)
fmt.Println(p) // 0x14000122008
fmt.Println(*p) // 0
*p = 10
fmt.Println(*p) // 10
提示
make返回的还是引⽤类型本⾝;⽽new返回的是指向类型的指针。后面再详细介绍