Golang学习——数组指针和指针数组的区别

Golang中数组指针和指针数组区别

  • 一.数组指针
    • 1.语法
    • 2.实例
    • 3.通过指针访问数组
  • 二.指针数组
    • 1.语法
    • 2.实例

区别二者,字面上只看 后两个字即可:
数组指针 :它是一个指针,但是数据类型为数组,或者说指向数组

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

一.数组指针

1.语法

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

var arrPtr *[size] Type

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

2.实例

一步一步创建,容易理解。
创建一个数组指针,并赋值:


var arrPtr * [4]int        // 创建一个指针 arrPtr,指向一个数组
var arr = [4]int{1,2,3,4}  // 创建一个数组并初始化
arrPtr = &arr              // 将数组 arr的地址赋值给arrPtr
fmt.Println("将 arr 的内存地址赋值给数组指针 arrPtr,   arrPtr=",ptr)

输出为:

将 arr 的内存地址赋值给数组指针 arrPtr,   arrPtr= &[1 2 3 4]

注意,输出的结果不是地址(不是16进制的数),在Golang中,直接输出的是

&[元素1 元素2 …]

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

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

输出为:

arr 数组的地址为:0xc00000c3c0
arrPtr 存储的地址为:0xc00000c3c0

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

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

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

输出为:

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

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

注意:仅对访问下标时,寻址运算符允许不写!

二.指针数组

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

1.语法

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

var ptrArr [size] *Type

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

2.实例

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

var ptrArr [4]*int  
a, b, c, d := 1, 2, 3, 4

arr2 := [4]int{a, b, c, d}  // 拷贝四个变量的值为函数组元素
fmt.Println("数组 arr2 :", arr2)

ptrArr = [4]*int{&a, &b, &c, &d} // 存的都是内存地址
fmt.Println("指针数组 ptrArr :", 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 都是值类型,各自改变,互不影响

以上就是在学习Golang数组指针和指针数组时的一些笔记和感悟。

总结一下,数组指针和指针数组这两个概念的区分,记住两点即可:

  • 后两字是啥,则它就表示啥
  • 定义时,最先写的 代码 就已经表示了其是数组还是指针

你可能感兴趣的:(Golang学习笔记)