首页 > 其他分享 >go语言基础-指针

go语言基础-指针

时间:2023-08-04 14:45:12浏览次数:32  
标签:语言 指向 i1 内存 var intP go 指针

不像 Java 和 .NET,Go 语言为程序员提供了控制数据结构的指针的能力;但是,你不能进行指针运算。通过给予程序员基本内存布局,Go 语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。

由于各种原因,指针对于使用面向对象编程的现代程序员来说可能显得有些陌生,不过我们将会在这一小节对此进行解释,并在未来的章节中展开深入讨论。

程序在内存中存储它的值,每个内存块(或字)有一个地址,通常用十六进制数表示,如:0x6b0820 或 0xf84001d7f0

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

下面的代码片段,可能输出 An integer: 5, its location in memory: 0x6b0820(这个值随着你每次运行程序而变化)。

var i1 = 5
fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)

这个地址可以存储在一个叫做指针的特殊数据类型中,在本例中这是一个指向 int 的指针,即 i1:此处使用 *int 表示。如果我们想调用指针 intP,我们可以这样声明它:

var intP *int

然后使用 intP = &i1 是合法的,此时 intP 指向 i1

(指针的格式化标识符为 %p

intP 存储了 i1 的内存地址;它指向了 i1 的位置,它引用了变量 i1

一个指针变量可以指向任何一个值的内存地址 它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上 * 号(前缀)来获取指针所指向的内容,这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。

当一个指针被定义后没有分配到任何变量时,它的值为 nil

一个指针变量通常缩写为 ptr

注意事项

在书写表达式类似 var p *type 时,切记在 * 号和指针名称间留有一个空格,因为 - var p*type 是语法正确的,但是在更复杂的表达式中,它容易被误认为是一个乘法表达式!

符号 * 可以放在一个指针前,如 *intP,那么它将得到这个指针指向地址上所存储的值;这被称为反引用(或者内容或者间接引用)操作符;另一种说法是指针转移。

对于任何一个变量 var, 如下表达式都是正确的:var == *(&var)

现在,我们应当能理解 pointer.go 的全部内容及其输出:

package main
import "fmt"
func main() {
    var i1 = 5
    fmt.Printf("An integer: %d, its location in memory: %p\n", i1, &i1)
    var intP *int
    intP = &i1
    fmt.Printf("The value at memory location %p is %d\n", intP, *intP)
}

输出:

An integer: 5, its location in memory: 0x24f0820
The value at memory location 0x24f0820 is 5

我们可以用下图来表示内存使用的情况

 

 为我们展示了指针对 string 的例子。

它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)

package main
import "fmt"
func main() {
    s := "good bye"
    var p *string = &s
    *p = "ciao"
    fmt.Printf("Here is the pointer p: %p\n", p) // prints address
    fmt.Printf("Here is the string *p: %s\n", *p) // prints string
    fmt.Printf("Here is the string s: %s\n", s) // prints same string
}

输出

Here is the pointer p: 0x2540820
Here is the string *p: ciao
Here is the string s: ciao

通过对 *p 赋另一个值来更改“对象”,这样 s 也会随之更改。

内存示意图如下:

 

注意事项

你不能获取字面量或常量的地址,例如:

const i = 5
ptr := &i //error: cannot take the address of i
ptr2 := &10 //error: cannot take the address of 10

所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如:pointer+2,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和 VB.NET 中的引用。

因此 p++ 在 Go 语言的代码中是不合法的。

指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。

另一方面(虽然不太可能),由于一个指针导致的间接引用(一个进程执行了另一个地址),指针的过度频繁使用也会导致性能下降。

指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数情况这会使你的代码结构不清晰。

如我们所见,在大多数情况下 Go 语言可以使程序员轻松创建指针,并且隐藏间接引用,如:自动反向引用。

对一个空指针的反向引用是不合法的,并且会使程序崩溃:

package main
func main() {
    var p *int = nil
    *p = 0
}
// in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
// runtime error: invalid memory address or nil pointer dereference

 

标签:语言,指向,i1,内存,var,intP,go,指针
From: https://www.cnblogs.com/songyunjie/p/17605881.html

相关文章

  • go语言基础-时间和日期
    time 包为我们提供了一个数据类型 time.Time(作为值使用)以及显示和测量时间和日期的功能函数。当前时间可以使用 time.Now() 获取,或者使用 t.Day()、t.Minute() 等等来获取时间的一部分;你甚至可以自定义时间格式化字符串,例如: fmt.Printf("%02d.%02d.%4d\n",t.Day(),t.Mon......
  • go语言基础-strings和strconv包
    作为一种基本数据结构,每种语言都有一些对于字符串的预定义处理函数。Go中使用 strings 包来完成对字符串的主要操作。前缀和后缀HasPrefix() 判断字符串 s 是否以 prefix 开头:strings.HasPrefix(s,prefixstring)boolHasSuffix() 判断字符串 s 是否以 suffix......
  • 指针跃动与神州租车(上海)达成战略合作
    近日,一则好消息传来,指针跃动与神州租车(上海)达成战略合作,经过双方精心合作和紧密协调,我们成功地完成了这次取送车业务,顺利交付了所有车辆,神州租车(上海)对服务的高度评价让我们倍感欣慰。据悉,此次取送车业务是指针跃动今年业务发展的重点之一,为了确保取送车服务的质量,我们从服......
  • go语言基础-基本类型和布尔
    这部分讲解有关布尔型、数字型和字符型的相关知识。表达式是一种特定类型的值,它可以由其他的值以及运算符组合而成。每个类型都定义了可以和自己结合的运算符集合,如果你使用了不在这个集合中的运算符,在编译时获得编译错误。一元运算符只可以用于一个值的操作(作为后缀),而二元运算......
  • C语言.多级指针
    #include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){longaa=123;longaaa=&aa;//warning:initializationof‘longint’from‘longint*’makesintegerfrompointerwithoutacast//这里,编译器......
  • 指针进阶(C语言)
    指针进阶头文件#include<stdio.h>#include<stdlib.h>#include<string.h>字符指针intmain(){//字符指针chararr1[]="abcdef";chararr2[]="abcdef";char*p1="abcdef";char*p2="abcdef";......
  • 4 抽象工厂方法 -- go语言设计模式
    工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。因此,可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是本文将要学习的......
  • Qt 在线程中invokeMethod采用QueuedConnection模式,调用带指针参数槽,实际不会调用
    widgetObject有操函数Test:voidTest(int*v);在线程中调用Test,会被忽略,实际不会调用。QMetaObject::invokeMethod(widgetObject,"Test",Qt::QueuedConnection,Q_ARG(int*,&v));下面是网上找的理由: 在同一个线程中当信号和槽都在同一个线程中时,值传递参数和引用传递参数有......
  • linux上使用yum部署mongodb4.2+分片副本
    来源:https://blog.51cto.com/wutengfei/5937039系统配置Linux是有文件句柄限制的,而且默认不是很高,一般都是1024,作为一台生产服务器,其实很容易就达到这个数量。为防止服务因toomanyopenfiles错误出现宕机,这里需要对linux系统句柄数进行调整。##临时调整,系统重启即失效ulimit......
  • go语言基础-基础数据类型之常量
    常量使用关键字const定义,用于存储不会改变的数据。存储在常量中的数据类型只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。常量的定义格式:constidentifier[type]=value,例如:constPi=3.14159在Go语言中,你可以省略类型说明符[type],因为编译器可以根据变量的值来......