什么是指针

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

在上图中,变量 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. Linux-系统编程-知识点概述

    1.基本指令和5个背景知识(os.env.file.shell.权限) 2.开发环境:(vim.gcc.g++.gdb.ctags.make.Makefile.procbar) 3.进程1: 进程的基 ...

  2. Java并发编程实战

    代码中比较容易出现bug的场景: 不一致的同步,直接调用Thread.run,未被释放的锁,空的同步块,双重检查加锁,在构造函数中启动一个线程,notify或notifyAll通知错误,Object. ...

  3. Openvswitch手册(7): Interfaces

    我们来看Interfaces ofport: OpenFlow port number for this interface. type: system: An ordinary network de ...

  4. flask上下文详解

    一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...

  5. C#通过COM组件操作IE浏览器(四):实用代码总结

    //执行js方法 IHTMLWindow2 win = oDocument2.parentWindow; win.execScript("functiona();", " ...

  6. css浮动(float)及清除浮动的几种实用方法

    CSS浮动是现在网页布局中使用最频繁的效果之一,而浮动可以帮我们解决很多问题,那么就让我们一起来看一看如何使用浮动. 一.css浮动(float) (1)html文档流 自窗体自上而下分成一行一行,并 ...

  7. Android JNI 学习(三):JNI 数据类型和数据结构

    本文我们来讨论一下JNI如何将Java类型映射到本机C类型. 一.基本数据类型 如下图表整理了Java基本类型和native对应的关系: Java类型 Native类型 描述 boolean jboo ...

  8. LSTM和GRU

    LSTM和GRU LSTM 忽略偏置: \[\begin{align} i_t&=\sigma(x_t\cdot W_i+h_{t-1}\cdot U_i)\\ f_t&=\sigma ...

  9. dubbo实用知识点总结(三)

    1. 服务降级 2. 优雅停机 3. 主机绑定 4. 访问日志 5. Multicast注册中心 6. zookeeper注册中心 7. 推荐用法 8. 容量规划 9. 基准测试工具包

  10. 写给深圳首期Python自动化开发周未班的信

    你是否做了正确的决定? 深圳首期周未班的同学们大家好,我是Alex, 老男孩教育的联合创始人,Python项目的发起人,51CTO学院连续2届最受学员喜爱的讲师,中国最早一批使用Python的程序员, ...