Go语言指针详解
链客,专为开发者而生,有问必答!
此文章来自区块链技术社区,未经允许拒绝转载。

不像 Java 和 .NET,Go语言为程序员提供了控制数据结构的指针的能力;但是,并不能进行指针运算。通过给予程序员基本内存布局,Go语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。
指针(pointer)概念在 Go 语言中被拆分为两个核心概念:
类型指针,允许对这个指针类型的数据进行修改。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。
切片,由指向起始元素的原始指针、元素数量和容量组成。
受益于这样的约束和拆分,Go 语言的指针类型变量拥有指针的高效访问,但又不会发生指针偏移,从而避免非法修改关键性数据问题。同时,垃圾回收也比较容易对不会发生偏移的指针进行检索和回收。
切片比原始指针具备更强大的特性,更为安全。切片发生越界时,运行时会报出宕机,并打出堆栈,而原始指针只会崩溃。
C/C++中的指针
说到 C/C++ 中的指针,会让许多人“谈虎色变”,尤其对指针偏移、运算、转换都非常恐惧。
其实,指针是使 C/C++ 语言有极高性能的根本,在操作大块数据和做偏移时方便又便捷。因此,操作系统依然使用C语言及指针特性进行编写。
C/C++ 中指针饱受诟病的根本原因是指针运算和内存释放。
C/C++ 语言中的裸指针可以自由偏移,甚至可以在某些情况下偏移进入操作系统核心区域。我们的计算机操作系统经常需要更新、修复漏洞的本质,是为解决指针越界访问所导致的“缓冲区溢出”。
要明白指针,需要知道几个概念:指针地址、指针类型和指针取值,下面将展开细说。
认识指针地址和指针类型
一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上 * 号(前缀)来获取指针所指向的内容,这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。
当一个指针被定义后没有分配到任何变量时,它的值为 nil。一个指针变量通常缩写为 ptr。
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go 语言中使用&作符放在变量前面对变量进行“取地址”操作。
格式如下:
ptr := &v // v的类型为T
其中 v 代表被取地址的变量,被取地址的 v 使用 ptr 变量进行接收,ptr 的类型就为*T,称做 T 的指针类型。*代表指针。
指针实际用法,通过下面的例子了解:
package main
import (
"fmt"
)
func main() {
var cat int = 1var str string = "banana"fmt.Printf("%p %p", &cat, &str)
}
运行结果:
0xc042052088 0xc0420461b0
代码说明如下:
第 8 行,声明整型 cat 变量。
第 9 行,声明字符串 str 变量。
第 10 行,使用 fmt.Printf 的动词%p输出 cat 和 str 变量取地址后的指针值,指针值带有0x的十六进制前缀。
输出值在每次运行是不同的,代表 cat 和 str 两个变量在运行时的地址。
在 32 位平台上,将是 32 位地址;64 位平台上是 64 位地址。
提示:变量、指针和地址三者的关系是:每个变量都拥有地址,指针的值就是地址。
从指针获取指针指向的值
在对普通变量使用&操作符取地址获得这个变量的指针后,可以对指针使用*操作,也就是指针取值,代码如下。
package main
import (
"fmt"
)
func main() {
// 准备一个字符串类型var house = "Malibu Point 10880, 90265"// 对字符串取地址, ptr类型为*stringptr := &house// 打印ptr的类型fmt.Printf("ptr type: %T\n", ptr)// 打印ptr的指针地址fmt.Printf("address: %p\n", ptr)// 对指针进行取值操作value := *ptr// 取值后的类型fmt.Printf("value type: %T\n", value)// 指针取值后就是指向变量的值fmt.Printf("value: %s\n", value)
}
运行结果:
ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265
代码说明如下:
第 10 行,准备一个字符串并赋值。
第 13 行,对字符串取地址,将指针保存到 ptr 中。
第 16 行,打印 ptr 变量的类型,类型为 *string。
第 19 行,打印 ptr 的指针地址,每次运行都会发生变化。
第 22 行,对 ptr 指针变量进行取值操作,value 变量类型为 string。
第 25 行,打印取值后 value 的类型。
第 28 行,打印 value 的值。
取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址(&)操作,可以获得这个变量的指针变量。
指针变量的值是指针地址。
对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
使用指针修改值
通过指针不仅可以取值,也可以修改值。
前面已经使用多重赋值的方法进行数值交换,使用指针同样可以进行数值交换,代码如下:
package main
import “fmt”
// 交换函数
func swap(a, b *int) {
// 取a指针的值, 赋给临时变量tt := *a// 取b指针的值, 赋给a指针指向的变量*a = *b// 将a指针的值赋给b指针指向的变量*b = t
}
func main() {
// 准备两个变量, 赋值1和2
x, y := 1, 2// 交换变量值swap(&x, &y)// 输出变量值fmt.Println(x, y)
}
运行结果:
2 1
代码说明如下:
第 6 行,定义一个交换函数,参数为 a、b,类型都为 *int,都是指针类型。
第 9 行,将 a 指针取值,把值(int类型)赋给 t 变量,t 此时也是 int 类型。
第 12 行,取 b 指针值,赋给 a 变量指向的变量。注意,此时*a的意思不是取 a 指针的值,而是“a指向的变量”。
第 15 行,将 t 的值赋给 b 指向的变量。
第 21 行,准备 x、y 两个变量,赋值 1 和 2,类型为 int。
第 24 行,取出 x 和 y 的地址作为参数传给 swap() 函数进行调用。
第 27 行,交换完毕时,输出 x 和 y 的值。
*操作符作为右值时,意义是取指针的值;作为左值时,也就是放在赋值操作符的左边时,表示 a 指向的变量。其实归纳起来,*操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值;当操作在左值时,就是将值设置给指向的变量。
如果在 swap() 函数中交换操作的是指针值,会发生什么情况?可以参考下面代码:
package main
import “fmt”
func swap(a, b *int) {
b, a = a, b
}
func main() {
x, y := 1, 2swap(&x, &y)fmt.Println(x, y)
}
运行结果:
1 2
结果表明,交换是不成功的。上面代码中的 swap() 函数交换的是 a 和 b 的地址,在交换完毕后,a 和 b 的变量值确实被交换。但和 a、b 关联的两个变量并没有实际关联。这就像写有两座房子的卡片放在桌上一字摊开,交换两座房子的卡片后并不会对两座房子有任何影响。
示例:使用指针变量获取命令行的输入信息
Go 语言的 flag 包中,定义的指令以指针类型返回。通过学习 flag 包,可以深入了解指针变量在设计上的方便之处。
下面的代码通过提前定义一些命令行指令和对应变量,在运行时,输入对应参数的命令行参数后,经过 flag 包的解析后即可通过定义的变量获取命令行的数据。
获取命令行输入:
package main
// 导入系统包
import (
"flag""fmt"
)
// 定义命令行参数
var mode = flag.String(“mode”, “”, “process mode”)
func main() {
// 解析命令行参数flag.Parse()// 输出命令行参数fmt.Println(*mode)
}
将这段代码命名为main.go,然后使用如下命令行运行:
$ go run flagparse.go --mode=fast
命令行输出结果如下:
fast
代码说明如下:
第 10 行,通过 flag.String,定义一个 mode 变量,这个变量的类型是 *string。后面 3 个参数分别如下:
参数名称:在给应用输入参数时,使用这个名称。
参数值的默认值:与 flag 所使用的函数创建变量类型对应,String 对应字符串、Int 对应整型、Bool 对应布尔型等。
参数说明:使用 -help 时,会出现在说明中。
第 15 行,解析命令行参数,并将结果写入创建的指令变量中,这个例子中就是 mode 变量。
第 18 行,打印 mode 指针所指向的变量。
由于之前使用 flag.String 已经注册了一个 mode 的命令行参数,flag 底层知道怎么解析命令行,并且将值赋给 mode*string 指针。在 Parse 调用完毕后,无须从 flag 获取值,而是通过自己注册的 mode 这个指针,获取到最终的值。代码运行流程如下图所示。
图:命令行参数与变量的关系
创建指针的另一种方法——new() 函数
Go 语言还提供了另外一种方法来创建指针变量,格式如下:
new(类型)
一般这样写:
str := new(string)
*str = “ninja”
fmt.Println(*str)
new() 函数可以创建一个对应类型的指针,创建过程会分配内存。被创建的指针指向的值为默认值。
相关文章:

java基础--日期--练习集锦
题目1 --日期 借助随机数,创建一个从1995.1.1 00:00:00 到 1995.12.31 23:59:59 之间的随机日期 package date;import java.util.Date;public class TestDate {public static void main(String[] args) {long second 1000;long minute 60*second;long hour minut…

python多变量非线性拟合_python实现多变量线性回归(Linear Regression with Multiple Variables)...
本文介绍如何使用python实现多变量线性回归,文章参考NG的视频和黄海广博士的笔记现在对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(x1,x2,...,xn)表示为:引入x01,…

【bzoj3150】 cqoi2013—新Nim游戏
www.lydsy.com/JudgeOnline/problem.php?id3105 (题目链接) 题意 在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又…

再见,Python!你好,Go语言
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 AI 前线导读:Go 语言诞生于谷歌,由计算机领域的三位宗师级大牛 Rob Pike、Ken Thompson 和 Robert Griesemer 写成。由于出身…

tensorflow intel platform 优化
intel平台优化 TensorFlow *是深度学习领域中主要使用的机器学习框架,要求高效利用计算资源。 为了充分利用英特尔架构和提高性能,TensorFlow *库已经使用英特尔MKL-DNN原语进行了优化,该原语是深度学习应用的流行性能库。 已进行优化的平台 …

basePath = request.getScheme()+://+request.getServerName()+:+r
basePath request.getScheme()"://"request.getServerName()":"r (2014-06-30 18:29:54) 转载▼标签: 宠物 分类: JavaString path request.getContextPath();String basePath request.getScheme()"://"request.getSe…

python dump函数_python中实现php的var_dump函数功能
最近在做python的web开发(原谅我的多变,好东西总想都学着。。。node.js也是),不过过程中总遇到些问题,不管是web.py还是django,开发起来确实没用php方便,毕竟存在的时间比较短,很多不完善的地方。比如我在调…

Go语言的Channel文章,整个人都感觉不好了
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 Go的Channel是一个很强大的并发数据模型,在一个发送者和多个消费者情况下工作得最好,但是如果是多个发送者,那么…
图书管理系统(源码)
本文demo下载地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId1070 实例使用java语言实现了一个网页版的图片管理系统, 系统前端使用bootstrap技术,可以进行浏览器适配, 实现功能: 管理图书管书, 管理图书借还信息࿰…

linux 如何禁用账号和解除禁用账号
把账号禁用可以有几个方法:1. # usermod -L <username> # usermod -U <username> // 解除禁用2. 修改/etc/passwd文件,可以有几个地方1)把第二个字段中的"x"变成其它的字符,该账号就不能…

maya批量命名插件_教你玩转MAYA的四十二精华造诣(第一期)
最近在整理文档时发现我收藏了一篇关于MAYA应用技巧的文章,突然有兴趣看了看,结果发现老版本MAYA中的某些内容很多已经无法应用于新版本。我又上网查了一下,结果发现网上好多帖子和我收藏的这篇内容基本一致,看来好多都是转载和抄…

Go语言开发常见陷阱,你遇到过几个?
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 Go作为一种简便灵巧的语言,深受开发者的喜爱。但对于初学者来说,要想轻松驾驭它,还得做好细节学习工作。 初学者…

sxoi爆炸祭
好吧,纯粹是去玩玩的,我这么一个弱省的蒟蒻,进队纯粹是开玩笑。。。。 Day0 去五中试机,感觉电脑手感不错,打了半个线段树的板子才发现试机要在自己的电脑上试,然后我无奈的搬东西(从26号搬到2号…

wiki多个文件一起导入_mac文件信息管理工具EagleFiler for Mac分享给大家
EagleFiler for mac使得管理您的信息方便。它可以让你存档和搜索邮件,网页,PDF文件,字处理文档,图像,等等。使用它可以从不同的来源收集信息。浏览不同类型的文件采用标准的三窗格界面。组织他们到文件夹中,…

【bzoj1951】 Sdoi2010—古代猪文
http://www.lydsy.com/JudgeOnline/problem.php?id1951 (题目链接) 题意 废话一堆。。求解:$$g^{\sum_{d|n} C_n^d}~mod~p$$ Solution 真的是数论经典题,什么都用上了。 因为费马小定理,每$p-1$个$g$相乘会得到$1$,那么容易得到&…

区块链之智能合约详解
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 什么是智能合约? 智能合约又称智能合同,是由事件驱动的、具有状态的、获得多方承认的、运行在区块链之上的、且能够根据预设…

子类化内置类型
Python 2.2之后内置类型开始可以子类化了 但是,CPython中的内置类型不会调用用户重写的类的特殊方法。 PyPy的文档中描述了这个问题。subclasses-of-built-in-types 正式情况下,CPython 并没有官方规定内置类型的子类中重写的方法是否会被隐式调用。基本…

网上商城系统源代码_多用户系统商城授权有几种方式?
网上商城系统一般都需要获取正规授权才可以投入商业使用范围,许多系统开发商为了适应不同企业的需求提供了几种不同的授权方式,企业可以选择合适的方式获得系统的使用权。下面HiShop小编就来为大家介绍一下多用户商城系统的授权方式。一、多用户系统商城…

java学习:对synchronized的测试
平时对synchronized这个关键字没有太在意,对它的认识停留在粗略翻了一下百度百科的状态,百度百科对它的解释是: “Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候ÿ…

Selenium(3)
练习1:Ecshop 录制登录后退出业务 打开系统 存储页面的标题 a.点击"登录"按钮 b.输入用户名:testing 存储输入的用户名 c.输入密码:123456 d.点击"立即登录"按钮 …

php 爬虫_Rad爬虫结合W13Scan扫描器挖掘漏洞
一、背景这几天一直在研究W13Scan漏洞扫描器,因为对Python不是太熟悉,所以进度有点慢,一直没看懂怎么将代理请求的数据转发到扫描队列中去,决定先熟悉熟悉这个功能再说;Rad爬虫最近比较火,于是就是就选择它…

Python 爬取网页HTML代码
#/usr/bin/env python #-*- coding:utf-8 -*-import urllib2 import sys import chardetreq urllib2.Request("http://tycool.top/") content urllib2.urlopen(req).read() typeEncode sys.getfilesystemencoding()##系统默认编码 infoencode chardet.detect(con…

区块链兼容以太坊智能合约
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 引言 随着区块链技术以及应用的普及,越来越多的区块链出现在大众视野中。由于区块链技术的开源特性,任何公司和个人都可以…

Linux常用命令--网终设置
1、把自己(sa)添加到sudoers配置文件中,以便于获取权限 vim /etc/sudoers 编辑文件(部分centOS版本没有vim命令,则用vi即可) 找到【root ALL(ALL) ALL】语句,在下面添加: sa ALL…

python示例异常处理与程序调试_笔记:Python异常处理与程序调试
Python异常处理与程序调试Python提供了强大的异常处理机制,通过捕获异常可以提高程序的健壮性。异常处理还具有释放对象,中止循环的运行等作用。在程序运行的过程中,如果发生了错误,可以返回事先约定的一个错误代码。"try...…

js传入参数为字符串问题
示例: var device_mac"11qweq234ert";//第一种方式会报错:Onclick SyntaxError: identifier starts immediately after numeric literal,数字后面紧跟着字符这种写法只有device_mac是数字的时候是正确的。传入的为字符串则应该使用…

区块链热度背后的资本市场
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 进入2018年之后大家对于加密数字货币以及区块链等话题都各自有各自的意见和想法,很多人觉得区块链技术和加密数字货币是泡沫ÿ…

袋鼠过河(动态规划)
题目描述 一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远。每个弹簧力量不同,用一个数字代表它的力量,如…

jenkins-svn配置
转载于:https://www.cnblogs.com/caer/p/5924337.html

python查看所有异常_如何获取python异常发生的实际行号?
如果你想按你描述的那样做from functools import wrapsimport sys, os, tracebackdef catch_exceptions(function):wraps(function)def decorator(*args, **kwargs):try:return function(*args, **kwargs)except Exception as e:exc_type, exc_obj, exc_tb sys.exc_info()prin…