什么是指针

指针是存储一个变量的内存地址的变量。

在上图中,变量 b 的值是 156,存储在地址为 0x1040a124 的内存中。变量 a 存储了变量 b 的地址。现在可以说 a 指向 b

指针的声明

指向类型 T 的指针用 *T 表示。

让我们写一些代码。

package main

import (
"fmt"
) func main() {
b := 255
var a *int = &b
fmt.Printf("Type of a is %T\n", a)
fmt.Println("address of b is", a)
}

& 操作符用来获取一个变量的地址。在上面的程序中,第 9 行我们将 b 的地址赋给 aa 的类型为 *int)。现在我们说 a 指向了 b。当我们打印 a 的值时,b 的地址将会被打印出来。程序的输出为:

Type of a is *int

address of b is 0x1040a124

你可能得到的是一个不同的 b 的地址,因为 b 可以在内存中的任何地方。

指针的空值

指针的空值为 nil 。

package main

import (
"fmt"
) func main() {
a := 25
var b *int
if b == nil {
fmt.Println("b is", b)
b = &a
fmt.Println("b after initialization is", b)
}
}

在上面的程序中,b 的初始值为 nil。接着将 a 的地址赋值给 b。程序的输出为:

b is <nil>
b after initialisation is 0x1040a124

指针解引用

解引用指针的意思是通过指针访问被指向的值。指针 a 的解引用表示为:*a

让我们通过一个程序看一下它是怎么工作的。

package main
import (
"fmt"
) func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a)
}

上面程序的第10行,我们将 a 解引用并打印这个解引用得到的值。和我们预期的一样,程序打印的是 b 的值。程序的输出为:

address of b is 0x1040a124
value of b is 255

让我们再写一个程序,该程序使用指针改变 b 的值。

package main

import (
"fmt"
) func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a)
*a++
fmt.Println("new value of b is", b)
}

在上面的程序中,我们将 a 指向的值自增 1,这样做也改变了 b 的值,因为 a 指向 b。因此 b 的值变为 256。程序的输出为:

address of b is 0x1040a124
value of b is 255
new value of b is 256

传递指针给函数

package main

import (
"fmt"
) func change(val *int) {
*val = 55
}
func main() {
a := 58
fmt.Println("value of a before function call is",a)
b := &a
change(b)
fmt.Println("value of a after function call is", a)
}

在上面的程序中,第 14 行,我们将指向 a 的指针 b 传递给函数 change。在函数 change 内部,第 8 行,通过解引用修改了 a 的值。程序的输出如下:

value of a before function call is 58
value of a after function call is 55

不要传递指向数组的指针给函数,而是使用切片

假设我们需要通过函数修改一个数组。一个办法是将数组的指针作为参数传递给函数。

package main

import (
"fmt"
) func modify(arr *[3]int) {
(*arr)[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(&a)
fmt.Println(a)
}

在上面的程序中,第13行,数组 a 的地址传递给了函数 modify。在第8行的 modify 函数中,我们通过解引用的方式将数组的第一个元素赋值为 90。程序输出为:[90 90 91]

a[x] 是 (*a)[x] 的简写,因此上面的程序中,(*arr)[0] 可以替换为 arr[0]。让我们用这种简写方式重写上面的程序:

package main

import (
"fmt"
) func modify(arr *[3]int) {
arr[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(&a)
fmt.Println(a)
}

程序的输出依然是:[90 90 91]

虽然可以通过传递数组指针给函数的方式来修改原始数组的值,但这在 Go 中不是惯用的方式,我们可以使用切片完成同样的事情。

让我们用切片的方式重写上面的程序:

package main

import (
"fmt"
) func modify(sls []int) {
sls[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(a[:])
fmt.Println(a)
}

在上面的程序中,第13行,我们传递了一个切片给 modify 函数。在函数内部,切片的第一个元素被修改为 90。程序的输出为:[90 90 91]。所以请不要以数组指针作为参数传递给函数,而是使用切片:)。这样的代码更加简洁,在 Go 中更常被使用。

Go 不支持指针运算

Go 不支持其他语言(比如C)中的指针运算。

package main

func main() {
b := [...]int{109, 110, 111}
p := &b
p++
}

上面的程序将报错:main.go:6: invalid operation: p++ (non-numeric type *[3]int)


												

go里面的指针用法的更多相关文章

  1. Leetcode刷题之矩阵中的指针用法

    矩阵中的指针用法 1 快慢指针 ​ Leetcode27移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度.不要使用额外的数组 ...

  2. C# this指针用法

    this指针是什么: 这里有一些面向对象编程的概念需要说明:类(Class)的概念和对象(Object)的概念类是对事物概括,也是C#编码时所有代码归属的基本单位:而对象是对类的实例化,也就是C#里n ...

  3. c++ 智能指针用法详解

    本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被c++11弃用. 为什么要使用智能 ...

  4. C和C指针小记(九)-指针用法1

    1. *p++ 最常用的一个指针的用法,就是在循环中用来迭代. *p++ 共有3步操作: 1.++操作符把p所指向的内存中的值复制一份 2.++操作符把p加1(实际是一个p所指内存单元的大小,这也是编 ...

  5. typedef函数指针用法

    typedef void(*vp)(); 将vp声明为一个函数指针类型,该类型的指可以针指向一个没有参数,带空返回值的函数. 调用方法vp p;创建一个vp类型的函数指针p void print(vp ...

  6. c语言指针用法

    一.指针 int t 定义整型变量 int *p p为指向整型数据的指针变量 int a[n] 定义整型数组a,它有n个元素 int *p[n] 定义指针数组p,它由n个指向整形数据的指针元素组成 i ...

  7. C++中const指针用法汇总

    这里以int类型为例,进行说明,在C++中const是类型修饰符: int a; 定义一个普通的int类型变量a,可对此变量的值进行修改. const int a = 3;与 int const a ...

  8. C语言的指针用法:输入一堆字符,把非字母的删去。

    char *p,a[20]; int i; gets(a);    //这个语句不同于getchar(),后者只能一次输入一个,而前者可以一次输完所有的字符!!! p=a;        //这个语句 ...

  9. C语言之指针用法总结

    C语言指针概述:1.计算机系统中,无论是存入或是取出数据都需要与内存单元打交道,物理器件通过地址编码寻找内存单元.2.地址编码是一种数据,C语言的指针类型正是为了表示这种计算机所特有的地址数据.3.存 ...

随机推荐

  1. RabbitMQ in Action(5): Clustering and dealing with failure

    Batteries included: RabbitMQ clustering The clustering built in to RabbitMQ was designed with two go ...

  2. SQL Server AlwaysOn搭建

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/高性能解决方案 概述 环境: 域服务器:windows server 2008 R2 SP1,192.168.2.10 DNS:1 ...

  3. 快速找出网站中可能存在的XSS漏洞实践(一)

    一.背景 笔者最近在慕课录制了一套XSS跨站漏洞 加强Web安全视频教程,课程当中有讲到XSS的挖掘方式,所以在录制课程之前需要做大量实践案例,最近视频已经录制完成,准备将这些XSS漏洞的挖掘过程记录 ...

  4. Javascript高级编程学习笔记(66)—— 事件(10)变动事件

    变动事件 DOM2级的变动事件,能在DOM中的一部分发生变化时给出提示 变动事件是为XML或HTML DOM 设计的,并不特定于某种语言 DOM2级定义了如下变动事件: DOMSubtreeModif ...

  5. Javascript高级编程学习笔记(47)—— 元素遍历

    元素遍历 为了方便我们使用JS来遍历文档中的元素,W3C在原来的基础之上提出了 Element Traversal 规范 这一规范主要就是为了统一浏览器对文档中节点解析不一致的问题. 比如在某些浏览器 ...

  6. Eclipse 中构建 Maven 项目的完整过程 - SpringBoot 项目

    进行以下步骤的前提是你已经安装好本地maven库和eclipse中的maven插件了(有的eclipse中已经集成了maven插件) 一.Maven项目的新建 1.鼠标右键---->New--- ...

  7. WPF中TreeView控件的使用案例

    WPF总体来说还是比较方便的,其中变化最大的主要是Listview和Treeview控件,而且TreeView似乎在WPF是一个备受指责的控件,很多人说他不好用.我这个demo主要是在wpf中使用Tr ...

  8. 彻底填平Static坑(细节决定成败)

    static 学习的过程就是填坑的过程,可不要偷懒想着跳过去,你现在跳过去,就相当于给自己挖了一个坑,你迟早会掉进去的,为了避免不掉坑,所以,努力填坑吧! 一.如果没有static会怎样? 需求: 1 ...

  9. Spring Boot(八):RabbitMQ 详解

    RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将 RocketMQ 捐献给了 ...

  10. docker镜像打包save,载入load,启动run

    docker打包,针对的是镜像,而不是运行中的容器. 查看当前系统的镜像文件:docker images 将当前运行中的,已经自定义修改后的容器保存为新的镜像. docker commit ce11e ...