Golang Go语言中关于数组指针的疑问

发布于 1周前 作者 wuwangju 来自 Go语言

面在学 go 指针的时候,认为 指针变量存放的是 内存地址值 , *操作符就是能拿到该内存储存的值

然后将指针结合到数组的时候(数组指针),发现直接用指针就能操作数组了,而不需要用*

普通变量指针操作

package main

import “fmt”

func main(){ a := 10 p := &a *p = 20 fmt.Print(a) //20 }

上面的一般都没什么问题,然后是数组指针

package main

impotr “fmt”

func main(){ pArr := [3]int{12,2,9} pArr[0] = 16 pAdd := &pArr (*pAdd)[0] = 444

fmt.Printf("pArr[0] %v\n",pArr[0])
fmt.Printf("pAdd[0] %v\n",pAdd[0])
fmt.Printf("pAdd %v\n",pAdd)
fmt.Printf("pArr  %v\n",pArr)
fmt.Printf("pAdd 指向的东西 %v\n",*pAdd)
fmt.Printf("pArr[0]的地址  %v\n",&pArr[0])
fmt.Printf("pAdd[0]的地址  %v\n",&pAdd[0])
fmt.Printf("(*pAdd)[0]的地址  %v\n",&(*pAdd)[0])

/*output
    pArr[0] 444
    pAdd[0] 444
    pAdd &[444 2 9]
    pArr  [444 2 9]
    pAdd 指向的东西 [444 2 9]
    pArr[0]的地址  0xc04200c2e0
    pAdd[0]的地址  0xc04200c2e0
    (*pAdd)[0]的地址  0xc04200c2e0
*/

}

注意到上面,

直接操作数组 pArr[0] = 16 我可以理解 通过指针找到数组进而操作数组 (*pAdd)[0] = 16 我也可以理解

但是~!

直接通过指针就能操作到原来的数组是什么操作? pAdd[0] = 16 这我就不是很理解了... 这样子写 字面意思上 操作的是指针,但是原来的数组也跟着改变了,输出后发现大家指向的都是同一个地址值

pArr[0]的地址 0xc04200c2e0
pAdd[0]的地址 0xc04200c2e0
(*pAdd)[0]的地址 0xc04200c2e0

ps:题主没有 c 这种指针型语言的基础,望理解

最后想问,用指针直接操作数组这样的情况要怎么去理解呢?


Golang Go语言中关于数组指针的疑问

更多关于Golang Go语言中关于数组指针的疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

15 回复

最后想问,用指针直接操作数组这样的情况要怎么去理解呢?
其实数组指针指向的是数组的第一个元素的地址。所以你输出的都是同一个地址

更多关于Golang Go语言中关于数组指针的疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


可能你看下数据结构就明白为什么了吧

pAdd[0] = 16 其实就是 (*pAdd)[0] = 16…go 语言不能直接操作指针的,只能操作指针指向区域吧.

以上纯属不负责任猜测,有问题楼下大佬指正.

印象中(很多年不写了),在 C 语言里面,有两种对数组元素间接寻址的方法,但其实是一种:
ArrayName[下标 or 偏移量]
pointerToArray[下标 or 偏移量]

pAdd[0] = 16 --------- 你可能迷惑的是,这个相当于 " pointerToArray[下标 or 偏移量] ",怎么没有前面的
号了?

按我的肤浅观察(我对 Go 的认识很肤浅),实际上是 Go 语言对此做了处理,这种处理,很可能基于这些认知:
1,避免双重指针 " **pointerToPointer ",或更多重的指针
2,指针变量的地址值是无意义的,所以你对指针变量取地址,结果得到的不是指针变量本身的地址,而是指针所指内存的地址,所以 pArr 和 pAdd 是一模一样的。这点可能让 C/C++同学很不爽

通过这类简化和限制处理,大概能够避免常见的指针错误吧

其实还是喜欢汇编 /C/C++,操纵的是真实的物理机器,完全掌控一切

go 里面为了方便程序员,有很多隐式操作,这里是隐式解引用了。

https://golang.org/ref/spec#Index_expressions

For a of pointer to array type:

a[x] is shorthand for (*a)[x]


1. C 里面一样是 pointerToArray[index]的写法
2. 你说的“对指针变量取地址,结果得到的不是指针变量本身的地址,而是指针所指内存的地址”根本就没这回事,上面的代码就没有打印 &pAdd,你可以试试看

5 楼真相了, 写几行代码你看一下,但是指针要理解的话,多看文档和实践,不是一下子你就能理解了,我感觉的话。
<br>package main<br><br>import (<br> f "fmt"<br><br>)<br><br>type stu struct {<br> name string<br>}<br><br>var book = make(map[string]int64)<br><br>//http 客户端编写<br>func main(){<br> //值类型示例: array 和 struct<br> a := &amp;[4]int64{1,2,44}<br> student := new(stu)<br> <a target="_blank" href="http://student.name" rel="nofollow noopener">student.name</a> = "狗朗" //这两行等效于 student = &amp;stu{name: "狗朗"}<br><br> //引用类型示例:slice 和 map<br> s := &amp;[]int64{4,5,6}<br> book["瞎卡拉卡环游记"] = 666<br> b := &amp;book<br><br> //值类型变量的显示解引用(操作指针)<br> f.Println((*a)[0],(*student).name) // 输出:1 狗朗<br> //值类型变量的隐式解引用(不操作指针)<br> f.Println(a[0],<a target="_blank" href="http://student.name" rel="nofollow noopener">student.name</a>) // 输出:1 狗朗<br><br> //引用类型变量的显示解引用(操作指针)<br> f.Println((*s)[0], (*b)["瞎卡拉卡环游记"]) // 输出:4 666<br><br> //引用类型变量的隐式解引用(操作指针)<br> //f.Println(s[0],b["瞎卡拉卡环游记"]) --语法错误,因为引用类型-&gt;无隐式解引用特性<br>}<br>

http 那行自动忽略

倒数第三行括号内应是:不操作指针

兄弟你真是明灯啊,已感谢~

谢谢指正!

仔细看了一下,对指针取地址以后确实是获取了指针的地址,而不是指针所指内容的地址,也即,跟 C 语言一致

C 语言里面指针操作数组是 *(pointerToArray +下标) = newValue,不是方括号。多年不用,也是记忆不清

还是 c/c++好,写出来的代码是什么样子,执行的效果就是什么样子。
现在的语言,有点过度封装了,天晓得一个简单的语句,背后隐藏了多少复杂的,不可告人的操作和深坑。

C 还行,C++就别这么说了八,坑最多的

在Go语言中,关于数组指针的理解是掌握Go语言内存管理和数据传递的重要一环。

首先,要明确的是,Go语言中的数组是值类型。这意味着当你将一个数组赋值给另一个变量时,会复制整个数组的内容。因此,如果数组较大,这种复制操作可能会带来性能上的开销。

为了优化这种性能开销,我们可以使用数组指针。数组指针是指向数组首元素的指针。通过传递数组指针,我们实际上传递的是指针的值(即地址),而不是数组本身的内容。这样,函数或方法就可以通过指针直接访问和修改原始数组,而无需进行复制。

在Go语言中,你可以通过取地址操作符(&)来获取数组的地址,从而得到一个指向数组的指针。例如,arr := [5]int{1, 2, 3, 4, 5} 定义了一个数组,ptr := &arr 则获取了该数组的地址,并将地址存储在指针变量 ptr 中。

需要注意的是,虽然数组指针可以提高性能,但在使用时也要小心,因为不当的指针操作可能会导致内存泄漏、野指针等安全问题。

总的来说,Go语言中的数组指针是一个强大的工具,可以帮助你优化性能并直接操作内存。但同时,也需要你具备扎实的内存管理知识和良好的编程习惯,以确保代码的安全和稳定。

回到顶部