Go语言之理解指针

1. 说一下内存

我们在编程的时候,实际上就是在操作内存,除非是进行IO操作写磁盘。其余的不管你是一半的变量还是Hibernate的Entity,都是在内存中闪转腾挪。

我上学的时候,C语言课程是第一门编程语言课程,其中最难的部分就是指针,而指针就是直接操作内存的,所谓的C语言是最接近底层的语言,其中很重要的原因就是以为C语言让程序员可以直接去动内存。

其实在很多年前,人们编程的时候绝对不像想在这么幸福,总是要直接操作内存的,而更久远一点的程序员们,要用汇编语言直接写指令,再久一点的程序员,就要在纸带上打孔,用01010这种二进制编码编程了。

我说了这么多,其实想说的是,现在的很多编程语言比如Java,其实是对程序员隐藏了其内存操作的细节的。

我们都知道Java有堆内存和栈内存,堆内存里是实际的对象,栈内存中的变量指向了对象,这里的指向,其实就是指针了。那么指向的是什么?有没有人曾经思考过这个问题,在内存中,如何快速的寻找一个值?

答案自然是地址,只有用地址访问是最快的。

内存结构

如上图所示,如果有一种低级语言,也许是这样的:

//我设计了一种运算符,[]内表示内存地址
var [1] = 101

这样就将内存地址1的块设置成了101。

现在时代进步了,我们发明了变量这个概念,其实就是给内存地址起了名字:

var a = 101

此时变量a就是地址1的别名了,可以这么理解。

2. 现在谈谈指针

那么指针是什么?指针的值是一个变量的地址,一个指针只是值所保存的位置。

下面写一段正确的Go代码,这段代码来自《The Go Programming Language》:

x := 1
p := &x
//打印1
fmt.Println(*p)
*p = 2
//打印2
fmt.Println(x)

这个时候画一个内存模型,应该是这样的:

指针1

&是取地址运算符,根据变量x,取到了相应的地址,此时如果打印p,得到的是一段类似这样的字符串:“0xc000016050”。

接下来利用*p=2这个语句将指针指向的值改成2,画成图是这样的:

修改指针值

看看,利用指针我根本不需要去知道变量叫什么,只要改指针就可以了。

下面再来一段代码,来源还是一样的:

package main

import "fmt"

func incr(p *int) int {
    *p++
    return *p
}

func main() {
    v := 1
    incr(&v)
    fmt.Println(incr(&v))
}

这段代码比较迷惑的地方在于*p++,程序最终的返回结果是3,注意,这一句只是将指针p所指向的值进行了递增操作,但是并没有变更p本身,因此画出图来是这样的:

修改指针值2

3. 搞点事情

如指针那张图,其实p也是内存中的一个地址,那么一定可以有一个指针指向它,这没毛病:

v := 1
p := &v
q := &p

此时的q就是一个指向指针的指针了。q得到的是p的地址,*q得到的就是p指向的值了。

指向指针的指针在C语言里常常会用到,我现在初学Go,也不知道会不会频繁使用,反正有个印象就好了。

你可能感兴趣的:(Go语言之理解指针)