通过指针修改数据

Modifying data via pointers

提问人:user3051040 提问时间:12/26/2019 最后编辑:Jonathan Halluser3051040 更新时间:12/26/2019 访问量:127

问:

https://play.golang.org/p/DOhYaiH53Ek

我不明白这个操作,也不了解一个指针如何能够修改它的即.我知道我一定误解了什么,但这段代码从字面上看似乎是自相矛盾的。*&p*pint() value NOT a memory addressvaluevalueX = valueY

//point

package main

import "reflect"

var pt int = 27

func main() {
    println(reflect.TypeOf(pt))
    println("pt = ", pt)   //value of pt
    println("&pt = ", &pt) //memory address of pt
    updatePointer(&pt)
    println("pt = ", pt) //value of pt
}

func updatePointer(p *int) { //requires memory address of an int
    println("&p = ", &p)                                //memory address of p
    println("p = ", p)                                  //memory address of pt
    println("*p before = ", *p)                         //value of pt
    println(*p == 27)                                   //true
    *p = 14                                             //27 = 14??????????
    println("*p =", *p)                                 //value of pt
    println(reflect.TypeOf(&pt) == reflect.TypeOf(*&p)) //true!!!?????
    println("*&p = ", *&p)                              //memory address which p's memory address evals to???? 0x800 (p) -> 0x900 (pt) = 0x800 (p)?
}

/*
Why can't I do the following?

func updatePointer(p *int){
    p = 14
    //OR
    &p = 14
    //OR
    *&p = 14
}
*/
指针 go 变量赋值 值运算符

评论


答:

2赞 peterSO 12/26/2019 #1

简化。例如

package main

import "fmt"

func f(q *int) {
    fmt.Println(*q, q, &q, "f")
    *q = 14
    fmt.Println(*q, q, &q, "f")
}

func main() {
    var i int = 27
    var p *int = &i
    fmt.Println(*p, p, &p, i, "main")
    f(p)
    fmt.Println(*p, p, &p, i, "main")
}

输出:

27 0x40e020 0x40c138 27 main
27 0x40e020 0x40c148 f
14 0x40e020 0x40c148 f
14 0x40e020 0x40c138 14 main

错误:

/*
func g(r *int) {
    // cannot use 14 (type int) as type *int in assignment
    r = 14
    // cannot assign to &r
    &r = 14
    // cannot use 14 (type int) as type *int in assignment
    *(&r) = 14
}
*/

游乐场: https://play.golang.org/p/Hwe3anFBTfD


在 Go 中,所有参数都是按值传递的,就像按赋值传递一样。指向 int 的指针通过值 () 传递给函数 。指针 , 是 的副本,用于修改 , , 的值,取消引用类型为类型。piq = pfqpi*q = 14*q*intint


函数编译器错误消息解释了为什么这些语句是非法的。例如,is 是 , 是 类型 。g*&r = 14*(&r) = 14r = 14cannot use 14 (type int) as type *int in assignmentr*int


引用:

围棋之旅

Go 编程语言规范

2赞 Brits 12/26/2019 #2

首先考虑一下,让我们简化示例(删除所有不相关的东西)*&p

var pt int = 27
p := &pt // because &pt is passed as the argument into updatePointer
*p = 14  // This assigns 14 to whatever p points to (i.e. pt)
println(reflect.TypeOf(&pt) == reflect.TypeOf(*&p))

*&什么都不做(我看不出有什么理由在实际应用程序中使用它);该语句获取 P(位)的地址,然后获取结果指向 () 的内容。所以这是一个被重写的&pp

println(reflect.TypeOf(&pt) == reflect.TypeOf(p))

p指向 so(根据定义,这意味着 )。这意味着它们是同一件事,所以当然会具有相同的类型。ptp == &pt*p == pt

那么为什么有效呢?你说“*p 是一个 int() 值,而不是一个内存地址,能够修改它的值”,但这并不完全是规范所说的:*p = 14

对于指针类型为 *T 的操作数 x,指针间接 *x 表示 x 指向的 T 类型的变量。如果 x 为 nil,则 尝试计算 *x 将导致运行时崩溃。

所以所说的是将 p 指向的变量设置为 14。*p = 14

现在让我们看看你的第二个问题:

// Why can't I do the following?

func updatePointer(p *int){
    p = 14
    //OR
    &p = 14
    //OR
    *&p = 14
}

所以 p 是指向整数的指针(这就是这个意思)。Say 是尝试将指针(而不是 int)设置为值 14。14 是 int 而不是指针,因此编译器错误。*intp = 14cannot use 14 (type int) as type *int in assignment

&p = 14就是说把 p 的地址设为 14。 所以获取地址会给你一个(指向指向 int 的指针的指针)。您将得到的编译器错误是,这是因为 的结果不可寻址。你可以通过说p*int**intcannot assign to &p&p

x := &p
x = 14

这将根据我上面所说的内容为您提供您可能期望的错误:.cannot use 14 (type int) as type **int in assignment

*&p = 14基本上等同于说(它得到 p 的地址,然后得到 whis 的结果点将是 p)。p=14

指针可能会变得非常混乱(尤其是在人为的例子中),本文可能会帮助您理解。