指针
要明白指针,需要知道几个概念:指针地址、指针类型和指针取值
import "fmt"
func main() {
var a int = 20;
var ip *int
ip = &a; // 将a的门牌号取出来放入ip中
fmt.Printf("a变量的地址:%x\n" , &a) //a变量的地址:c042054080
fmt.Printf("ip指针变量存储的是a变量的门牌号: %x\n", ip) //ip指针变量存储的是a变量的门牌号: c042054080
fmt.Println("通过门牌号取相应内存取出值:", *ip) //通过门牌号取相应内存取出值: 20
}
认识指针地址和指针类型
一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。当一个指针被定义后没有分配到任何变量时,它的默认值是nil。指针变量通常缩写为ptr。
每个变量在运行时都有一个地址,这个地址表示变量在内存中的位置。Go语言中使用在变量名前面添加&操作符(前缀)来获取变量的内存地址(取地址操作),格式如下:
ptr := &v // v 的类型为 T
其中 v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为*T
,称做 T 的指针类型,*
代表指针。
package main
import (
"fmt"
)
func main() {
var cat int = 1
var str string = "banana"
fmt.Printf("%p %p", &cat, &str)
}
从指针获取指针指向的值
当使用&操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*操作符,也就是指针取值,代码如下。
package main
import "fmt"
func main() {
// 准备一个字符串类型
var house = "Malibu Point 10880, 90265"
// 对字符串取地址, ptr类型为*string
ptr := &house
// 打印ptr的类型
fmt.Printf("ptr type: %T\n", ptr)
// 打印ptr的指针地址
fmt.Printf("address: %p\n", ptr)
// 对指针进行取值操作
value := *ptr
// 取值后的类型
fmt.Printf("value type: %T\n", value)
// 指针取值后就是指向变量的值
fmt.Printf("value: %s\n", value)
}
取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
- 对变量进行取地址操作使用&操作符,可以获得这个变量的指针变量。
- 指针变量的值是指针地址。
- 对指针变量进行取值操作使用*操作符,可以获得指针变量指向的原变量的值。
使用指针修改值
通过指针不仅可以取值,也可以修改值。
package main
import "fmt"
func main() {
var house = "Malibu Point 10880, 90265"
ptr := &house
*ptr = "change";
fmt.Printf("value: %s\n", *ptr)
}
创建指针的另一种方法——new() 函数
Go语言还提供了另外一种方法来创建指针变量,格式如下:
new(类型)
一般这样写:
str := new(string)
*str = "Go语言教程"
fmt.Println(*str)
new()函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。
package main
import "fmt"
type name int8
type first struct {
a int
b bool //未初始化的变量自动赋上初始值
name
}
func main() {
va := new(first)
va.a = 1
va.name = 11
fmt.Println(va, va.b, va.a, va.name) //&{1 false 11} false 1 11
var vb = first{1, false, 2}
fmt.Println(vb, vb.a, vb.b, vb.name) //{1 false 2} 1 false 2
var ip *first = &vb;
fmt.Println(&vb) // &{1 false 2}
fmt.Println(*ip, (*ip).a, (*ip).b, (*ip).name) //{1 false 2} 1 false 2
fmt.Println(ip, ip.a, ip.b, ip.name) //1 false 2
// 取出ip的地址然后去访问值
fmt.Println(*(&ip), *(&ip.a), *(&ip.b), *(&ip.name)) //&{1 false 2} 1 false 2
// 取出ip的地址
fmt.Println(&ip, &ip.a, &ip.b, &ip.name) //0xc042004030 0xc042008110 0xc042008118 0xc042008119
fmt.Println(&vb, &vb.a, &vb.b, &vb.name) //&{1 false 2} 0xc042008110 0xc042008118 0xc042008119
}