指针的意义(附代码示例)

108 阅读4分钟

对于我们中的一些人来说,如果不是从低级别的高级语言(如C)开始编程,"指针 "的概念是陌生的。当我开始学习Go时,我花了一段时间才完全掌握了 "指针 "是什么。我先是在Golang中理解了这个概念,然后回到C和C++中,意识到这是同样的东西!在这里,我试图解释一下这个概念。

以下是我对 "指针 "的解密尝试。但在此之前,让我们来谈谈地址。

地址:代码和数据的生存空间

一个地址是对一个特定内存位置的引用。代码和变量被加载到内存中供处理器使用。对于像a + b (假设ab 是整数或任何在特定语言中可以操作的操作数+ )这样的简单计算是可能的。处理器必须知道它们在内存中的精确位置,这样它就可以挑选它们,然后对它们进行加法;处理器必须知道这些变量的地址

指针:邻里关系专家

那么,什么是指针?形象地说,指针就像邻居家的白胡子。他是一个知道邻居中的每个人,他们住在哪里,他们做什么,等等。如果你想知道变量a 的地址,就可以去找他。

在Golang中,一个指针持有一个值的内存地址。这就是它的全部作用。

这里有一个例子:

package main

import "fmt"

func main() {
  var number int = 33

  var addressOfNumber *int = &number // Pointer to the `number` variable

  fmt.Print(addressOfNumber)
}

// Prints: 0xc0000b4008

在Go中,& 操作符产生了一个指向其操作数的指针,这样&number 就变成了指向变量number 的指针。&number 知道number 住在0xc0000b4008

var addressOfNumber *int = &number 是如何声明一个指针变量的。一个隐式声明是这样的: 。addressOfNumber := &number

好的。所以,现在我们知道指针在内存中保存着数值的地址。

棒极了!

那么,重点是什么呢?(无双关之意)

为了说明指针的意义,让我们假设你在一个工资为1500美元的地方工作。一个新的老板来了,要求你的初级开发人员写一个程序,使每个人的工资翻倍!大家都很兴奋。大家都很兴奋,你也很高兴!

但是,你的开发人员带着这个来了,要求进行代码审查:

package main

import "fmt"

func doubleWage(wage int) {
  wage *= 2
}

func main() {
  var wage int = 1500 // Salary in USD

  doubleWage(wage)

  fmt.Println(wage)
}

看了这个,你认为你的新工资会是多少?1,500美元还是3,000美元?乍一看,这看起来会使你的工资翻倍,达到3000美元,但事实并非如此!而这正是指点迷津的时候了。

为什么我们没有得到加薪

我们的工资在之前的项目中保持不变,即1500美元。这是因为Golang是一种按价值传递的语言。Pass-by-value是一种评估策略,根据维基百科的说法。

在逐值传递中,参数表达式被评估,得到的值被绑定到函数中的相应变量上(经常是通过将值复制到一个新的内存区域)。如果函数或过程可以为其参数赋值,则只对其局部变量进行赋值。也就是说,当函数返回时,任何传入函数调用的东西在调用者的范围内都是不变的。

所以这就是我们上面的程序中发生的事情:

func main() {
  var wage int = 1500 // Original value of `wage`

  doubleWage(wage)    // COPY `wage`

  fmt.Println(wage)   // Print original value of `wage`
}

doubleWage(wage) 完成了工资翻倍的工作,但我们对翻倍后的数值没有做任何处理!

为加薪而战

有一个特殊的运算符我们还没有提到......* 。当我们把它与指针一起使用时,我们不是得到某个值的地址,而是得到一个值本身。

从这一点来看:

  var number int = 33

  var addressOfNumber *int = &number // Pointer to the `number` variable

我们知道addressOfNumber 是一个指针(返回number 的地址),如果我们做*addressOfNumber ,我们会得到33 ,即值本身。我们可以继续做类似于*addressOfNumber = 55 的事情,这将把number 的值设置为55;我们把这称为 "取消引用"。

有了新发现的知识,我们可以在这里修复我们的原始程序,以获得我们应得的报酬:

package main

import "fmt"

func doubleWage(wage *int) {
  *wage *= 2
}

func main() {
  var wage int = 1500 // Salary in USD

  doubleWage(&wage)

  fmt.Println(wage)
}

// Prints 3000!

我们已经让我们的doubleWage 接受一个指针作为参数,并且用*wage *= 2 修改了指针所指向的东西。现在要使用它,因为doubleWage 指向一个地址,我们必须用&wage 传递一个地址给它,这就够了。

指针允许我们跳转范围,而这,女士们先生们,就是指针的意义所在。