求问:指针作为函数参数的问题

tooyan · 2020-03-02 14:41:51 · 993 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2020-03-02 14:41:51 的主题,其中的信息可能已经有所发展或是发生改变。

代码如下

package main

import "fmt"

func swap(a, b *int) (*int, *int) {
    fmt.Printf("a2: %v %p\n", *a, a)
    a, b = b, a
    fmt.Printf("a3: %v %p\n", *a, a)
    return a, b
}

func main() {
    a := 3
    b := 4
    fmt.Printf("a1: %v %p\n", a, &a)
    c, d := swap(&a, &b)
    fmt.Printf("a4: %v %p\n", a, &a)
    fmt.Println(*c, *d)
}

打印输出:

a1: 3 0xc0000120b8

a2: 3 0xc0000120b8

a3: 4 0xc0000120d0

a4: 3 0xc0000120b8

问题:

1.golang指针类型无法运算,为什么swap函数中 a,b=b,a可以执行?

2.从swap中打印的a2、a3来看,a指向的地址已经发生了变化。操作的是指针类型,跳出swap函数之后a应该还是修改后的值,为什么a4与a3的打印结果不一致?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

993 次点击  ∙  1 赞  
加入收藏 微博
7 回复  |  直到 2020-03-06 11:16:57
focusonline
focusonline · #1 · 5年之前

楼主可能对指针和参数传递理解不深? 一句话解释这个就是此a,b非彼a,b

tooyan
tooyan · #2 · 5年之前
focusonlinefocusonline #1 回复

楼主可能对指针和参数传递理解不深? 一句话解释这个就是此a,b非彼a,b

&a就是指向a的地址啊,而且第一行和第二行打印的值和地址都是一致的。 指针传参,修改的不就是指针指向的内存吗

jarlyyn
jarlyyn · #3 · 5年之前
tooyantooyan #2 回复

#1楼 @focusonline &a就是指向a的地址啊,而且第一行和第二行打印的值和地址都是一致的。 指针传参,修改的不就是指针指向的内存吗

你改的a的这个*int变量的值,又没改它对应的对象……

focusonline
focusonline · #4 · 5年之前
tooyantooyan #2 回复

#1楼 @focusonline &a就是指向a的地址啊,而且第一行和第二行打印的值和地址都是一致的。 指针传参,修改的不就是指针指向的内存吗

你如果要改指针的值,必须要使用指向指针的指针. 你传入的这个指针,实际上是被复制到堆栈的一个引用而已. 在里面交换了引用a,b, 并没有能改变实际的指针. 亲, 你的C语言看样子没掌握好,有空还是温习温习吧. go语言虽然很简单,但是有些东西也容易绕晕人的.

wxb
wxb · #5 · 5年之前
package main

import "fmt"

func swap(newA, newB *int) (*int, *int) {
    // 这里的newA执行的是调用中传递进来的变量地址,也就是说main中传递尽量的变量a得的地址(&a)被复制保存到了这个newA变量,newB同理
    fmt.Printf("a2: %v %p\n", *newA, newA)   // 所以这里输出的和main输出保持一致;是:a2: 3 0xc0000120b8
    // 这一步将newA和newB执行的内存地址做了交互;也就是说newA和newB变量的指向做了变更
    newA, newB = newB, newA
    // 此时打印newA时,其实打印的是调用者最初传递进来的newB执行内存地址的值和地址 
    fmt.Printf("a3: %v %p\n", *newA, newA)
    return newA, newB
}

func main() {
    a := 3
    b := 4
    // 这一步不用解释
    fmt.Printf("a1: %v %p\n", a, &a)
    // c指向的是b内存地址;d指向的是a内存地址
    c, d := swap(&a, &b)
    // 这里a的内存地址没变,所以值也不变。记住上面swap(&a, &b)调用时,是将&a, &b的内存地址传给了swap函数的形参newA和newB;swap内部交互newA和newB变量的内存指向,并不会影响这里a和b的指向(也就是一楼说的“此a,b非彼a,b”);但是如果swap中修改newA或者newB指向内存地址中的值,就会影响这里a和b的值
    fmt.Printf("a4: %v %p\n", a, &a)
    fmt.Println(*c, *d)
}

稍微做个修改,楼主可能会清晰点

tooyan
tooyan · #6 · 5年之前
wxbwxb #5 回复

```go package main import "fmt" func swap(newA, newB *int) (*int, *int) { // 这里的newA执行的是调用中传递进来的变量地址,也就是说main中传递尽量的变量a得的地址(&a)被复制保存到了这个newA变量,newB同理 fmt.Printf("a2: %v %p\n", *newA, newA) // 所以这里输出的和main输出保持一致;是:a2: 3 0xc0000120b8 // 这一步将newA和newB执行的内存地址做了交互;也就是说newA和newB变量的指向做了变更 newA, newB = newB, newA // 此时打印newA时,其实打印的是调用者最初传递进来的newB执行内存地址的值和地址 fmt.Printf("a3: %v %p\n", *newA, newA) return newA, newB } func main() { a := 3 b := 4 // 这一步不用解释 fmt.Printf("a1: %v %p\n", a, &a) // c指向的是b内存地址;d指向的是a内存地址 c, d := swap(&a, &b) // 这里a的内存地址没变,所以值也不变。记住上面swap(&a, &b)调用时,是将&a, &b的内存地址传给了swap函数的形参newA和newB;swap内部交互newA和newB变量的内存指向,并不会影响这里a和b的指向(也就是一楼说的“此a,b非彼a,b”);但是如果swap中修改newA或者newB指向内存地址中的值,就会影响这里a和b的值 fmt.Printf("a4: %v %p\n", a, &a) fmt.Println(*c, *d) } ``` 稍微做个修改,楼主可能会清晰点

newA和a的唯一联系就是newA的值是a的地址,所以对newA进行操作不会改变a,只有对*newA操作才会改变a的值。感觉清晰好多,感谢!

Sinbad
Sinbad · #7 · 5年之前

想要修改变量的地址,首先需要的是一个指针变量才可以,并且需要用到多重指针。 正常变量的地址是固定的。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传