Image Description

了解 Go语言指针之前,先回顾计算机内存和指针的知识。

什么是内存

计算机的内存 RAM 用来存储数据,可以把它想象成一堆有序的盒子,一个接一个的排成一排,每个盒子被唯一的数字标记,数字就是盒子的地址依次递增,也就是内存的地址。

每个盒子(内存单元格)用来存储一个值。如果知道一个单元格的地址,就可以通过这个地址读取单元格里的内容,也可以用新的值代替之前单元格里之前的值。

什么是指针

指针是一个指向另一个变量内存地址的值。

指针指向变量的内存地址,指针就像该变量值的内存地址一样。

代码示例

package main

import (
  "fmt"
)

func main() {
    a := 200
    b := &a
    fmt.Println("a -->", a)
    fmt.Println("*b -->", *b)
    fmt.Println("&a -->", &a)
    fmt.Println("b -->", b)

    *b++
    fmt.Println("a -->", a)
    fmt.Println("*b -->", *b)
}

变量 a的值是200,变量 b的值就是变量 a的内存地址。变量 b是一个指针,指向 a所在的内存地址。

*b++ 是对变量 b指向的内存地址取值后再对该值加 1,即对变量 a的值加1。

执行结果如下:

a --> 200

*b --> 200

&a --> 0xc4200160b0

b --> 0xc4200160b0

a --> 201

*b --> 201

代码示例

package main

import (
  "fmt"
)

type packet struct {
    id   int
    size int
}

var (
    p packet
    q *packet
)

func main() {
    p = packet{
      id:   1,
      size: 2,
    }
    q = &p
    fmt.Println("p -->", p)
    fmt.Println("q -->", q)
    fmt.Println("*q -->", *q)
    fmt.Println("&p -->", &p)
    fmt.Println("&q -->", &q)
    fmt.Println("p.size -->", p.size)
    fmt.Println("(*q).size -->", (*q).size)
    fmt.Println("q.size -->", q.size)
}

首先定义了一个结构类型 packet,接着声明了两个变量 p 和 q。 p 是一个普通的 packet结构,q 是一个 packet类型的指针。

初始化 p之后,指针 q的值是 p的地址,q 是一个指向 p内存地址的指针。执行结果如下:

p --> {1 2}
q --> &{1 2}
*q --> {1 2}
&p --> &{1 2}
&q --> 0x113e040
p.size --> 2
(*q).size --> 2
q.size --> 2

从上可以看出,q 的值是对 p进行取地址操作。

*q 是对 q指向的内存地址取值,取出的是 p的值。

&q 是指针指向的 q所在的内存地址的值。