【Go语言】Go语言中的指针

Go语言中的指针

变量的本质是对一块内存空间的命名,我们可以通过引用变量名来使用这块内存空间存储的值,而指针则是用来指向这些变量值所在内存地址的值。

注:变量值所在内存地址的值不等于该内存地址存储的变量值。

Go语言中,如果一个变量是指针类型的,可以用这个变量来存储指针类型的值。

以下是Go语言中,指针的简单使用:

a := 100
var ptr *int  // 声明指针类型
ptr = &a      // 初始化指针类型值为变量 a 
fmt.Println(ptr)
fmt.Println(*ptr)

如上代码中,变量 ptr 就是一个指针类型,表示指向存储 int 类型值的指针,ptr本身是一个内存地址,因此需要通过内存地址进行赋值(通过 &a 获取变量 a 所在的内存地址),赋值之后,可以通过 *ptr 获取指针指向内存地址所存储的变量值,这种操作称为“间接引用”。

1 指针类型的声明和初始化

指针变量在传值时之所以可以节省内存空间,是因为指针指向的内存地址的大小是固定的,在32位机器上占4个字节,在64位机器上占8个字节,这与指针指向内存地址存储的值类型无关。

var ptr *int
fmt.Println(ptr)
fmt.Println(*ptr)
​
a := 100
var ptr *int
ptr = &a
fmt.Println(ptr)
fmt.Println(*ptr)

指针被声明后,没有指向任何的内存空间,此时指针的值是零值nil,可以通过&变量名的方式获取变量对应的内存地址,再将其赋值给指针,这样就完成指针的初始化操作。

也能够通过 := 实现指针类型的初始化,代码如下所示:

b := 100
ptr2 := &b
fmt.Printf("%p\n", ptr2)
fmt.Printf("%d\n", *ptr2)

通过 := 进行指针的初始化,无需声明指针类型,底层会自动判断。

此外,也可以通过内置函数 new 声明指针:

ptr3 := new(int)
*ptr3 = 100

通过 new 初始化的指针,已经指向的内存地址,此时内存地址中存储的值是该指针类型的零值。

2 通过指针传值

通过指针传值能够节省内存空间,此外还能够在调用函数中实现对变量值的修改,因为直接修改了内存地址上存储的值,而不是值拷贝。

func swap(a, b int) {
    a, b = b, a
    fmt.Println(a, b)
}
func pointerSwap(a, b *int) {
    *a, *b = *b, *a
    fmt.Println(*a, *b)
}
​
// 值拷贝
func PointerValueCopyExample() {
    a := 10
    b := 20
    fmt.Println("直接进行值拷贝")
    swap(a, b)
    fmt.Println(a, b)
    fmt.Println("通过指针进行值交换")
    pointerSwap(&a, &b)
    fmt.Println(a, b)
}

如上运行结果,可以发现通过指针进行值交换,变量的值也会发生变化,这里是因为指针的交换是直接修改内存地址上存储的值,调用完交换函数后,对应的内存空间值也进行了交换,因此外部的指针指向变量地址存储的值也发生了变化。

3 unsafe.Pointer

unsafe.Pointer 是特别定义的一种指针类型,能够包含任意类型变量的地址,以下是Go语言官方的定义:

  • 任何类型的指针都可以被转化为 unsafe.Pointer;

  • unsafe.Pointer 可以被转化位任何类型的指针;

  • unintpr 可以被转化为 unsafe.Pointer;

  • unsafe.Pointer 可以被转化为 uintptr。

因此,unsafe.Pointer 可以在不同的指针类型之间做转化,从而可以表示任意可寻址的指针类型:

i := 10
var p *int = &i
var fp *float32 = (*float32)(unsafe.Pointer(p))
*fp = *fp * 10
fmt.Println(i)

如上代码中,首先是声明了一个int类型的指针 p 指向变量 i ,然后int类型的指针转化为unsafe.Pointer再转化为float32类型的指针,最终对p指向内存地址的变量进行修改,打印出来i的地址发生了变化。

unsafe.Pointer 是一个万能指针,可以在任何指针类型之间进行转化,绕过了Go语言的类型安全机制,因此是一个不安全的操作。

unsafe.Pointer 还可以与 uintptr 类型之间相互转化,uintptr 是 Go语言内置的可以用于存储指针的整型,而整型是可以进行运算的,因此将 unsafe.Pointer 转化为 uintptr 类型后,就可以让本不具备运算能力的指针具备了指针运算能力:

arr := [3]int{1, 2, 3}
ap := &arr
// unsafe.Sizeof 数组元素偏移量
// ap由unsafe.Pointer -> uintptr -> unsafe.Pointer
sp := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(ap)) + unsafe.Sizeof(arr[0])))
*sp += 3

这里,将arr数组的内存地址赋值给指针ap,通过unsafe.Pointer转化为uintptr类型,再加上数组中第一个元素的偏移量,就可以得到该数组中第二个元素的内存地址,最后通过unsafe.Pointer将其转化为int类型指针赋值给sp,修改sp指针指向内存地址的变量值。

通过如上操作,能够绕过Go语言中指针的安全限制,实现对指针的动态偏移和计算,但这样操作,如果数组发生了越界也不会报错,而是返回下一个内存地址的值,破坏了内存的安全限制,因此这个操作也是不安全的操作,尽量避免unsafe.Pointer的相关使用,必须使用时需要非常谨慎。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/415824.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[CSS]文字旁边的竖线以及布局知识

场景:文字前面常见加竖线。 .center-title { 常见内容color: #FFF;font-family: "Source Han Sans CN";font-size: 50px;font-style: normal;font-weight: 700;line-height: normal;position: relative; 要定位left: 16px; 这里是想拉开间距margin-b…

vmware中Numlock和caplock一直闪烁(更新时间24/2/28)

问题复现: 分析原因是:宿主机和vm虚拟机的这两个键未同步导致的异常 解决方法:将鼠标移动到点击虚拟机窗口以外的地方,按这两个键将其设置为打开状态即可解决

科技赋能,MTW400A为农村饮水安全打通“最后一公里”

日前,山东省政府纵深推进国家省级水网先导区建设,持续深化“水网”行动,着力构筑水安全保障网、水民生服务网、水生态保护网,建设水美乡村示范带、内河航运示范带、文旅融合示范带、绿色发展示范带,推动形成“三网四带…

微服务架构 SpringCloud

单体应用架构 将项目所有模块(功能)打成jar或者war,然后部署一个进程--医院挂号系统; > 优点: > 1:部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可。 > 2:技术单一:项目不需要复杂的技术栈,往往一套熟悉的…

目标检测——车辆数据集

一、背景介绍 VOC2005车辆数据集是PASCAL VOC挑战赛中的一个重要组成部分,该挑战赛始于2005年,旨在为计算机视觉领域的研究者和开发者提供一个统一的、标准化的评估平台。PASCAL VOC挑战赛不仅推动了图像识别、目标检测、图像分割等技术的发展&#xff…

textbox跨线程写入

实现实例1 实现效果 跨线程实现 // 委托,用于定义在UI线程上执行的方法签名 //public delegate void SetTextCallback(string text);public void textBoxText(string text){// 检查调用线程是否是创建控件的线程 if (textBox1.InvokeRequired){// 如果不是&#…

2.12冯诺依曼体系,各功能部件作用,简要工作流程

1)计算机由哪几部分组成?以哪部分为中心?2)主频高的CPU一定比主频低的CPU快吗?为什么?3)翻译程序、汇编程序、编译程序、解释程序有什么差别?各自的特性是什么?4)不同级别的语言编写的程序有什么区别&#…

华为OD技术面试案例3-2024年

技术一面: 1.手撕代码,算法题: 【最小路径和】 手撕代码通过,面试官拍了照片 2.深挖项目,做过的自认为最好的一个项目,描述做过的项目的工作过程,使用到哪些技术? 技术二面&…

单细胞Seurat - 细胞聚类(3)

本系列持续更新Seurat单细胞分析教程,欢迎关注! 维度确定 为了克服 scRNA-seq 数据的任何单个特征中广泛的技术噪音,Seurat 根据 PCA 分数对细胞进行聚类,每个 PC 本质上代表一个“元特征”,它结合了相关特征集的信息。…

枚举(蓝桥练习)

目录 一、枚举算法介绍 二、解空间的类型 三、循环枚举解空间 四、例题 (一、反倍数) (二、特别数的和) (三、找到最多的数) (四、小蓝的漆房) (五、小蓝和小桥的…

【JGit 】一个完整的使用案例

需求 生成一系列结构相同的项目代码,将这些项目的代码推送至一个指定的 Git 仓库,每个项目独占一个分支。 推送时若仓库不存在,则自动创建仓库。 分析 生成代码使用 Java 程序模拟,每个项目中模拟三个文件。Project.cpp 、Pro…

CUMT---图像处理与视觉感知---期末复习重点

文章目录 一、概述 本篇文章会随课程的进行持续更新中! 一、概述 1. 图像的概念及分类。  图像是用各种观测系统以不同形式和手段观测客观世界而获得的、可以直接或间接作用于人的视觉系统而产生的视知觉实体。  图像分为模拟图像和数字图像:(1) 模拟图…

Leetcode 第 385 场周赛题解

Leetcode 第 385 场周赛题解 Leetcode 第 385 场周赛题解题目1:3042. 统计前后缀下标对 I思路代码复杂度分析 题目2:3043. 最长公共前缀的长度思路代码复杂度分析 题目3:3044. 出现频率最高的质数思路代码复杂度分析 题目4:3045. …

【新书推荐】8.4 逻辑运算指令

本节内容:逻辑运算指令。8086 CPU逻辑运算指令包括NOT、AND、OR、XOR,除NOT指令外,均有两个操作数。逻辑运算指令影响状态标志位。 ■否操作指令NOT指令格式:NOT OPRD。将OPRD取反,然后送回OPRD。操作数可以是8位/16位…

Jetson系统烧录环境搭建

一 序言 Jetson 系列产品烧录系统的方法一般有两种,一种为使用 NVIDIA 官方提供 的 SDK manager 软件给 Jetson 设备烧录系统(请查看说明文档《Jetson 产品使用 SDKmanager 烧录系统》)。另一种即为当前文档所描述的,在安装 Ubun…

GZ036 区块链技术应用赛项赛题第10套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷(10卷) 任 务 书 参赛队编号: 背景描述 养老保险是对于老年人的最基本的生活保障。各种数据显示,当前的养老金市场规模庞大。2016年美国的养老金资…

403页面绕过

403页面绕过 文章目录 403页面绕过姿势一: 端口利用姿势二:修改HOST姿势三:覆盖请求URL姿势四:Referer标头绕过姿势五:代理IP姿势六:扩展名绕过 姿势一: 端口利用 拿到客户给的地址后,首先进行信息收集。端…

MySQL存储引擎及索引机制

MySQL技术——存储引擎和索引机制 一、存储引擎概述二、常见存储引擎的区别三、索引机制四、索引的底层实现原理五、InnoDB主键和二级索引六、聚集索引和非聚集索引七、哈希索引八、InnoDB的自适应哈希索引九、索引常见问题十、慢查询日志总结 一、存储引擎概述 插件式存储引擎…

【C++私房菜】序列式容器的迭代器失效问题

目录 一、list的迭代器失效 二、vector的迭代器失效 1、空间缩小操作 2、空间扩大操作 三、总结 在C中,当对容器进行插入或删除操作时,可能会导致迭代器失效的问题。所谓迭代器失效指的是,原先指向容器中某个元素的迭代器,在…

IDEA基础——Maven配置tomcat

配置方案 一、配置maven-tomcat plugin插件(只最高支持到tomcat 8)~~1.添加镜像源,获取tomcat 8插件配置~~~~1.1 在pom.xml里先添加镜像源~~~~1.2 添加tomcat插件配置~~ 2. 添加tomact官方发布的插件配置(无需添加镜像源&#xff…
最新文章