关于 go 数组指针的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
waibunleung
V2EX    Go 编程语言

关于 go 数组指针的疑问

  •  1
     
  •   waibunleung 2018-07-31 13:04:35 +08:00 2798 次点击
    这是一个创建于 2636 天前的主题,其中的信息可能已经有所发展或是发生改变。

    面在学 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 这种指针型语言的基础,望理解

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

    14 条回复    2018-07-31 22:51:10 +08:00
    KeepPro
        1
    KeepPro  
       2018-07-31 13:33:30 +08:00
    最后想问,用指针直接操作数组这样的情况要怎么去理解呢?
    其实数组指针指向的是数组的第一个元素的地址。所以你输出的都是同一个地址
    lifespy
        2
    lifespy  
       2018-07-31 13:42:03 +08:00
    可能你看下数据结构就明白为什么了吧
    leemove
        3
    leemove  
       2018-07-31 14:03:59 +08:00
    `pAdd[0] = 16` 其实就是 `(*pAdd)[0] = 16`...go 语言不能直接操作指针的,只能操作指针指向区域吧.

    以上纯属不负责任猜测,有问题楼下大佬指正.
    hyyou2010
        4
    hyyou2010  
       2018-07-31 14:11:47 +08:00
    印象中(很多年不写了),在 C 语言里面,有两种对数组元素间接寻址的方法,但其实是一种:
    ArrayName[下标 or 偏移量]
    *pointerToArray[下标 or 偏移量]

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

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

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

    其实还是喜欢汇编 /C/C++,操纵的是真实的物理机器,完全掌控一切
    heimeil
        5
    heimeil  
       2018-07-31 14:13:47 +08:00
    go 里面为了方便程序员,有很多隐式操作,这里是隐式解引用了。
    lk0317
        6
    lk0317  
       2018-07-31 14:50:44 +08:00   2
    https://golang.org/ref/spec#Index_expressions

    For a of pointer to array type:

    a[x] is shorthand for (*a)[x]
    kkurs
        7
    kkurs  
       2018-07-31 15:23:05 +08:00
    @hyyou2010
    1. C 里面一样是 pointerToArray[index]的写法
    2. 你说的“对指针变量取地址,结果得到的不是指针变量本身的地址,而是指针所指内存的地址”根本就没这回事,上面的代码就没有打印 &pAdd,你可以试试看
    Leigg
        8
    Leigg  
       2018-07-31 15:27:16 +08:00
    5 楼真相了, 写几行代码你看一下,但是指针要理解的话,多看文档和实践,不是一下子你就能理解了,我感觉的话。
    ```
    package main

    import (
    f "fmt"

    )

    type stu struct {
    name string
    }

    var book = make(map[string]int64)

    //http 客户端编写
    func main(){
    //值类型示例: array 和 struct
    a := &[4]int64{1,2,44}
    student := new(stu)
    student.name = "狗朗" //这两行等效于 student = &stu{name: "狗朗"}

    //引用类型示例:slice 和 map
    s := &[]int64{4,5,6}
    book["瞎卡拉卡环游记"] = 666
    b := &book

    //值类型变量的显示解引用(操作指针)
    f.Println((*a)[0],(*student).name) // 输出:1 狗朗
    //值类型变量的隐式解引用(不操作指针)
    f.Println(a[0],student.name) // 输出:1 狗朗

    //引用类型变量的显示解引用(操作指针)
    f.Println((*s)[0], (*b)["瞎卡拉卡环游记"]) // 输出:4 666

    //引用类型变量的隐式解引用(操作指针)
    //f.Println(s[0],b["瞎卡拉卡环游记"]) --语法错误,因为引用类型->无隐式解引用特性
    }
    ```
    Leigg
        9
    Leigg  
       2018-07-31 15:27:59 +08:00
    http 那行自动忽略
    Leigg
        10
    Leigg  
       2018-07-31 15:31:55 +08:00
    倒数第三行括号内应是:不操作指针
    waibunleung
        11
    waibunleung  
    OP
       2018-07-31 16:15:59 +08:00
    @lk0317 兄弟你真是明灯啊,已感谢~
    hyou2010
        12
    hyyou2010  
       2018-07-31 16:23:58 +08:00
    @kkurs 谢谢指正!

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

    C 语言里面指针操作数组是 *(pointerToArray +下标) = newValue,不是方括号。多年不用,也是记忆不清
    d18
        13
    d18  
       2018-07-31 17:40:45 +08:00
    还是 c/c++好,写出来的代码是什么样子,执行的效果就是什么样子。
    现在的语言,有点过度封装了,天晓得一个简单的语句,背后隐藏了多少复杂的,不可告人的操作和深坑。
    merin96
        14
    merin96  
       2018-07-31 22:51:10 +08:00
    @d18 C 还行,C++就别这么说了八,坑最多的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2604 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 12:42 PVG 20:42 LAX 05:42 JFK 08:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86