go 指针
anlondon Lv6

前言

最近在学习 go 语言,了解到指针,初看有些迷糊,自己仔细梳理了下,算是明白了,在此记录下。

说明

go 语言的指针借鉴了 c,所以很多地方都有共同的地方

一、内存结构

程序内所有的赋值取值,都是在内存中进行写入、读取操作。

而写入数据时,内存要保存数据的值、数据的类型、数据的名称以及数据的地址;

  • 内存的基本单位
    image

  • 多个单位组成的内存 图像表示
    image

二、指针运算符

首先看看指针运算所用到的符号

&【取地址】,取地址运算符;获取变量在内存中的地址

*【取值】,间接运算符/取消引用运算符;获取某个内存地址保存的值

功能介绍
1
2
3
4
5
//eg 1:
var number int = 10

fmt.Println("number内存地址为:", &number) //number内存地址为:0xc0000160a8
fmt.Println("number在内存的值为:", *(&number)) //number在内存的值为:10

上面案例就是一个简单明了的运算符使用

  • &:可以获取变量在内存中的地址
  • *:可以根据内存地址,取到该地址保存的值。因此也被称为指针。
使用

程序中一般用于将内存地址赋值给其他变量

1
2
3
4
5
//eg 2:
var number int= 5
var p *int= &number //*int:整形指针类型;用于接收整形变量在内存中的地址

fmt.Println("p在内存的值为:", p) //p在内存的值为:0xc0000160a8

go 语言中*int表示获取int类型变量在内存中的地址,也还有*string*float32等等。指针类型变量只能保存同一类型变量的地址

当然,在实际使用中,* 往往与 & 配合使用

1
2
3
4
5
6
7
8
9
//eg 3:
var number int= 5
var p *int= &number //*int:指针类型;

*p = 100 //将[p指向的地址]的值改为100 即*p=100 =>*(&number)=100 => number=100
fmt.Println("p在内存的值为:", p) //p在内存的值为:0xc0000160a8
fmt.Println("*p在内存的值为:", *p) //*p在内存的值为:100
fmt.Println("number在内存的值为:", number) //number在内存的值为:100
fmt.Println("number在内存的值为:", *(&number)) //number在内存的值为:100

解析:

var p *int= &number,保存的是number在内存中的地址

*p = 100 则相当于 *(&number)=100;等同于 number=100

因此*也被称为指针运算符;***不仅可以根据内存地址找到对应的值,还可以对该地址保存的值进行修改**

实际使用

上面代码仅作原理展示。
实际使用中往往用于不同方法间传递一个不受方法作用域限制的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//eg 4:
package main
import "fmt"

func changeValue(p int) {
p = 10
}

func swap(p *int) {
*p = 10
}

func main() {
var a int = 1

changeValue(a)
fmt.Println("a = ", a) // a = 1

swap(&a)
fmt.Println("a = ", a) // a = 10
}
扩展

*int*string*float32…等等这些被称为一级指针类型变量
**int**string**float32…等等被称为二级指针
指针类型可以有多级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//eg 5
package main

import "fmt"

func main() {
var number int = 5

var p *int = &number //*int:一级指针类型
var pp **int = &p //*int:二级指针类型;
var ppp ***int = &pp //*int:三级指针类型;

*p = 100 //将[p指向的地址]的值改为100 即*p=100 =>*(&number)=100 => number=100

fmt.Println("number在内存的值为:", number) //number在内存的值为: 100
fmt.Println("number在内存的地址为:", &number) //number在内存的地址为: 0xc0000160a8

fmt.Println("p在内存的值为:", p) //p在内存的值为: 0xc0000160a8
fmt.Println("*p在内存的值为:", *p) //*p在内存的值为: 100
fmt.Println("p在内存的地址为:", &p) //p在内存的地址为: 0xc000006028

fmt.Println("pp在内存的值为:", pp) //pp在内存的值为: 0xc000006028
fmt.Println("pp在内存的地址为:", &pp) //pp在内存的地址为: 0xc000006030

fmt.Println("ppp在内存的值为:", ppp) //ppp在内存的值为: 0xc000006030
fmt.Println("*ppp在内存的值为:", *ppp) //*ppp在内存的值为: 0xc000006028
fmt.Println("**ppp在内存的值为:", **ppp) //**ppp在内存的值为: 0xc0000160a8
fmt.Println("***ppp在内存的值为:", ***ppp) //***ppp在内存的值为: 100

***ppp = 200
fmt.Println("number在内存的值为:", number) //number在内存的值为: 200 即***pppp=200 =>*&*&*&number=100 => number=200
}

 Comments