go语言中的数组指针和指针数组的区别详解

1.介绍

大家知道C语言之所以强大,就是因为c语言支持指针,而且权限特别大,c语言可以对计算机中任何内存的指针进行操作,这样自然而然也会带来一些不安全的因素,所以在golang中,「取消了对指针的一些偏移,翻转等算术运算」(+、-、++、--)所以使用起来更安全。

  • 数组指针 :它是一个指针,但是数据类型为数组,或者说指向数组
  • 指针数组 :它是一个数组,该数组的元素都为地址值

2.数组指针

 在Go语言中,数组是一个固定长度的相同类型元素的序列。数组在声明时必须指定其长度,并且一旦创建,其长度就不能改变。

数组指针是指指向数组的指针。在Go语言中,你可以使用`&`操作符来获取数组的地址,从而创建一个指向数组的指针。数组指针的类型是`*[长度]类型`。

var 变量名 *[数组大小] 数组类型:

var arrPtr *[size] Type

初始化指针可以通过 new 函数来分配内存并返回指针的地址:

p := new(int)  // 分配一个 int 类型的内存,并将指针 p 指向该内存

 因为数组指针是一个指针,所以在定义时,先写 *, 表示定义一个指针,后面接数据类型

运行结果: 

 注意,输出的结果不是地址(不是 16 进制的数),在 Golang 中,直接输出的是&[元素 1 元素 2 ……]

我们可以输出一下二者的地址:

fmt.Printf("arr 数组的地址为:%p\n", &arr)   
fmt.Printf("arrPtr 存储的地址为:%p\n", arrPtr)

可以看到,它俩的输出时一样的,因为将数组 arr 的地址赋值给了 arrPtr,而 arrPtr 是一个指针,存储的是内存地址。

当然 arrPtr 也有自己的内存地址,我们可以看一下:

fmt.Printf("arrPtr 指针自己的地址为:%p\n", &arrPtr)

输出为:

arrPtr 指针自己的地址为:0xc000006028

2.1获取指针的地址和解使用

通过 & 操作符可以获取变量的地址,例如:

 x := 10p := &x  // 将指针 p 指向变量 x 的地址​a := 10b := &a // 将指针 b 指向变量 a 的地址

 使用 * 操作符可以解引用指针,获取指针指向的值 :

fmt.Println(*p)  // 输出指针 p 指向的值,即变量 x 的值

 输出结果:

 type of b:*inttype of c:intvalue of c:10

 取地址操作符 & 和取值操作符 * 是一对互补操作符,& 取出地址,* 根据地址取出地址指向的值。

3.通过指针访问数组

访问数组的元素可以通过下标来访问,比如:arr [0] 即可访问数组 arr 的第一个元素。

但是我们学习了指针数组,所以尝试使用指针数组来访问元素内容,在 Golang 中,取地址的操作为 * (寻址运算符) 。

因此,我们先取存储的地址 *arrPtr,访问到数组 ,然后再下标取值 *arrPt[0],代码如下:

*arrPtr[0]
  • 实际上,这段代码编译就会报错,因为在 Golang 中 * 寻址运算符和 [] 中括号运算符的优先级是不同的!
  • [] 中括号是初等运算符
  • 寻址运算符是单目运算符
  • 初等运算符的优先级是大于单目运算符的,因此先参与计算的是 arrPtr[0],arrPtr[0] 其实就是数组的第一个元素,就是数字 1。
  • 数字 1 必然是 int 类型,而不是一个地址,因此针对数字 1 使用 * 寻址运算符自然也就发生了错误。

解决问题的办法很简单,就是添加一个小括号,更改运算优先级即可:  

(*arrPtr)[0]
  • 不过因为 * 在 Golang 中,建立了 arrPtr := &arr 这种类似地址关系后,* 允许不写。
  • 所以,访问时候可以直接写成 arrPtr[0]。事实上在工作开发过程中,这种写法反而更加常见。实战代码:
fmt.Println("(*arrPtr)[0] 通过指针访问数组的第一个元素:", (*arrPtr)[0])
fmt.Println("arrPtr[0] 通过指针访问数组的第一个元素:", arrPtr[0])

 输出:

(*arrPtr)[0] 通过指针访问数组的第一个元素: 1
arrPtr[0] 通过指针访问数组的第一个元素: 1

4.指针数组

在Go语言中,指针数组是指一个数组,其元素时指针,指针元素通常用于存储多个指针,这些指针可以指向不同类型的数据结构,如结构体,数组,基本数据类型等等。

它是一个数组,该数组的元素都为地址值

var 变量名 [数组大小] * 数组类型:

var ptrArr [size] *Type

因为指针数组是一个数组,所以在定义时,先写 [size], 表示定义一个数组,后面再接指针 * 和 数组的数据类型

实例:
1. 创建一个数组指针, 数组的类型为 int,大小为 4,并赋值:

package main
import "fmt"func main() {var ptrArr [4]*int a,b,c,d := 1,2,3,4arr2 :=[4]int{a,b,c,d}//拷贝四个变量的值为函数组元素fmt.Println(arr2)ptrArr =[4]*int{&a,&b,&c,&d}//拷贝四个变量的地址值给函数组元素fmt.Println(ptrArr)
}

输出:

数组 arr2 : [1 2 3 4]
指针数组 ptrArr : [0xc0000140f0 0xc0000140f8 0xc000014100 0xc000014108]

2. 操作数据,查看变化

(1).arr2 的第一个元素改变,a 会不会变化,ptrArr 会不会变化?

arr2[0] = 100     
fmt.Println("arr2 的值为:", arr2)                      
fmt.Println("a 的值为;", a)               
fmt.Println("ptrArr 的值为;", *ptrArr[0])

输出:

arr2 的值为: [100 2 3 4]
a 的值为; 1
ptrArr 的值为; 1

先看 a 的值为 1 解释:

在 Golang 中,int,float,bool,string,array,struct 都属于值类型,数据拷贝时都是值拷贝,拷贝副本过来。

因此,尽管 arr2[0] = 100 执行了,只是修改了 arr2 的值,原来 a 的值不会受任何影响。因此,a 的值仍为 1

ptrArr 的值为 1 解释:

ptrArr 是指针数组, 该数组存储都是 指针,也就是 a,b,c,d 四个变量的内存地址。

其中,*ptrArr[0] 存储的是 a 的内存地址;a 没变, *ptrArr[0] 也不会变。所以输出仍为 1

我们可以查看一下 ptrArr[0] 的值和 a 的地址是否一致:

fmt.Println("ptrArr[0] 的值:", ptrArr[0])
fmt.Printf("a 的内存地址为:%p\n", &a)  // %p 占位符表示地址值

输出:

ptrArr[0] 的值: 0xc0000140f0
a 的内存地址为:0xc0000140f0

(2). 指针数组变化,a,b,c,d 会不会改变? 数组 arr2 会不会改变?

*ptrArr[0] = 1000  // 指针数组的第一个元素地址指向的值发生改变
fmt.Println("a 的值为:", a)       
fmt.Println("arr2 的值为:", arr2)

输出:

a 的值为: 1000
arr2 的值为: [100 2 3 4]

a 的值为: 1000 解析:

首先要明白一点:*ptrArr[0] = 1000 这段代码不会编译报错,因为 ptrArr 是指针数组,按照运算符的执行顺序,先 ptrArr[0] 获取 a 的地址,然后再 *a,这样获取的就是 a 的值

其实,解析的已经差不多了,ptrArr[0] 本来就是 a 的内存地址,所以 *ptrArr[0] = 1000 执行后,就改变了 a 的值

arr2 的值为: [100 2 3 4] 解析:

arr2 拷贝了 a,b,c,d 值的副本,a 的改变和 arr2 没有关系的,各不会受影响。a 和 arr2 都是值类型,各自改变,互不影响

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】分支和循环专题应用

分支和循环专题应用 1、随机数生成1.1rand1.2 srand函数介绍1.3 time函数介绍1.4 设置随机数的范围 2、猜数字游戏的代码及实现 通过了分支和循环的介绍学习之后,我们可以运用分支和循环语句写出一些有趣的代码了,让我们来一起探索吧! 写一个…

node.js 中的进程和线程工作原理

本文所有的代码均基于 node.js 14 LTS 版本分析 概念 进程是对正在运行中的程序的一个抽象,是系统进行资源分配和调度的基本单位,操作系统的其他所有内容都是围绕着进程展开的 线程是操作系统能够进行运算调度的最小单位,其是进程中的一个执…

远程桌面内网穿透是什么?有什么作用?

远程桌面内网穿透指的是通过特定技术手段,将处于内网中的电脑或服务器,通过外部网络(互联网)进行访问。内网穿透的主要作用是解决在内网环境下,远程设备与外部互联网之间的连接问题,允许用户从外部访问内网…

.Net Gacutil工具(全局程序集缓存工具)使用教程

GAC介绍: GAC(Global Assembly Cache)全局程序集缓存,是用于存放.Net应用程序共享的程序集。 像平常我们在Visual Studio中引用系统程序集时,这些程序集便来自于GAC。 GAC默认位置为:%windir%\Microsoft…

【ArcGIS】栅格计算器原理及案例介绍

ArcGIS:栅格计算器原理及案例介绍 栅格计算器(Raster Calculator)原理介绍案例案例1:计算栅格数据平均值 参考 栅格计算器(Raster Calculator)原理介绍 描述:在类似计算器的界面中,…

基于对数变换的图像美白增强,Matlab实现

博主简介:matlab图像处理(QQ:3249726188) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于对数变换的图像美白增强,用matlab实现。 一、案例背景和算法介绍 这次案例是美白算法&…

在实际LabVIEW开发中,哪些算法是常用的?

在LabVIEW的实际开发中,常用的算法主要集中在数据处理、控制系统、信号处理、图像处理等领域。以下是一些常用算法的介绍: 1. PID控制算法 PID(比例-积分-微分)控制是LabVIEW中常用的算法之一,广泛应用于工业自动化和…

剃(磨)前插齿刀设计计算开发第一步

之前接触滚刀比较多,渐开线齿轮滚刀的基准齿形的参数相对简单,都是由直线和圆弧组成的。插齿刀实质是一个开了前角后后角的“特殊齿轮”,在齿轮的齿形上增加“凸角”和“倒角”相对滚刀基准齿形就要复杂一些了: 要设计一款剃&…

深入分析计算机网络性能指标

速率带宽吞吐量时延时延带宽积往返时间RTT利用率丢包率图书推荐内容简介作者简介 速率 连接在计算机网络上的主机在数字信道上传送比特的速率,也称为比特率或数据率。 基本单位:bit/s(b/s、bps) 常用单位:kb/s&#x…

MacOS Catalina 从源码构建Qt6.2开发库之01: 编译Qt6.2源代码

安装xcode, cmake, ninja brew install node mac下安装OpenGL库并使之对各项目可见 在macOS上安装OpenGL通常涉及到安装一些依赖库,如MGL、GLUT或者是GLEW等,同时确保LLVM的OpenGL框架和相关工具链的兼容性。以下是一个基本的安装…

【算法】动态规划—编辑距离

题目 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符删除一个字符替换一个字符 思路分析 编辑距离问题就是给定两个字符串 s1 和 s2,只能用三种操作…

【隐私计算】Paillier半同态加密算法

一、何为同态加密(HE)? HE是一种特殊的加密方法,它允许直接对加密数据执行计算,如加法和乘法,而计算过程不会泄露原文的任何信息。计算的结果仍然是加密的,拥有密钥的用户对处理过的密文数据进…

编程辅助工具下一个热门应用场景是什么?(一)

🎁👉点击进入文心快码 Baidu Comate 官网,体验智能编码之旅,还有超多福利!🎁 本系列视频来自百度工程效能部的前端研发经理杨经纬,她在由开源中国主办的“AI编程革新研发效能”OSC源创会杭州站1…

QT之QML学习五:添加自定义Qml组件,以及组件管理

开发环境: 1、Qt 6.7.2 2、Pyside6 3、Python 3.11.4 4、Windows 10 重要的事情说三遍,使用自定义qml参考链接: Qt官网参考网址!!! 重要的事情说三遍,使用自定义qml参考链接: Qt官网参考网址!!! 重要的事情说三遍,使用自定义qml参考链接: Qt官网参考网址!!!…

6.1 溪降技术:绳结

目录 6.1 绳结电子书:绳结1级概览正确打结打绳结绳结组成部分学习术语八字套结(双八字结)观看技术步骤双重单结(反手结绳耳)观看技术步骤骡子结(驮马结)观看技术步骤 6.1 绳结 电子书&#xff1…

POI生成Excel文件增加数据验证(下拉序列)

POI版本为5.2.2 正常的如果不超过255字符的数据验证可以参照如下代码&#xff1a; /*** <p>设置某列的数据验证</p>* param Sheet 作用于哪一个sheet* param colIndex 需要增加数据验证的列的索引* String[] names 数据验证的序列&#xff0c;就是excel下拉列表的内…

持续集成与持续交付CI/CD

CI/CD 是指持续集成&#xff08;Continuous Integration&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;或持续交付&#xff08;Continuous Delivery&#xff09; 持续集成&#xff08;Continuous Integration&#xff09; 持续集成是一种软件开发实践&…

HTML贪吃蛇游戏

文章目录 贪吃蛇游戏 运行效果代码 贪吃蛇游戏 贪吃蛇是一款经典的休闲益智游戏。本文将通过HTML5和JavaScript详细解析如何实现一个简易版的贪吃蛇游戏。游戏的主要逻辑包括蛇的移动、碰撞检测、食物生成等功能。以下是游戏的完整代码及注释解析。&#xff08;纯属好玩&#…

(学习总结17)C++继承

C继承 一、继承的概念与定义继承的概念继承定义1. 定义格式2. 继承基类成员访问方式的变化 继承类模板 二、基类和派生类间的转换三、继承中的作用域隐藏规则 四、派生类的默认成员函数4个常见默认成员函数实现一个不能被继承的类 五、继承与友元六、继承与静态成员七、多继承及…

HTML 揭秘:HTML 编码快速入门

HTML 揭秘&#xff1a;HTML 编码快速入门 一 . 前端知识介绍二 . HTML 介绍三 . HTML 快速入门四 . HTML 编辑器 - VSCode4.1 插件安装4.2 修改主题配色4.3 修改快捷键4.4 设置自动保存4.5 创建 HTML 文件4.5 书写 HTML 代码4.6 常见快捷键 五 . 基础标签5.1 字体标签5.1.1 col…