Search code examples
gopointersslice

Dereferencing pointers in a slice does not seem to yield the initial value that the pointer was created from


I need to make a slice of pointers for a Go project I'm working on, that references the items in a slice. The expected behavior would be that I could modify one of the dereferenced items in the slice of pointers, and that would modify the original item in the normal list that it is pointing to. Modifying the original items would also be expected to show as the new value when dereferencing the pointers in the slice. However neither of these behaviors seem to work.

Here's some demo code I wrote to reproduce this.

package main

import "fmt"

func main() {
    var x []int = []int{5,4,3,2,1}
    var y *[]int = &x

    var g []*int
    for _, x := range x {
        g = append(g, &x)
    }

    fmt.Println("x, y, g, *g =")
    fmt.Println(x)
    fmt.Println(y)
    fmt.Println(g)
    printPtr(g)
    fmt.Println()
    fmt.Println()

    fmt.Println("Setting *g[0] to 10")
    *g[0] = 10
    
    fmt.Println("*g =")
    printPtr(g)
    fmt.Println()
    fmt.Println()

    fmt.Println("Setting x[1] to 17")
    x[1] = 17

    fmt.Println("x, y, *g =")
    fmt.Println(x)
    fmt.Println(y)
    printPtr(g)
    fmt.Println()
}

func printPtr(i []*int) {
    for _, v := range i {
        fmt.Print(*v)
        fmt.Print(" ")
    }
}

This code prints:

x, y, g, *g =
[5 4 3 2 1]
&[5 4 3 2 1]
[0x140000a6018 0x140000a6020 0x140000a6028 0x140000a6030 0x140000a6038]
5 4 3 2 1 

Setting *g[0] to 10
*g =
10 4 3 2 1 

Setting x[1] to 17
x, y, *g =
[5 17 3 2 1]
&[5 17 3 2 1]
10 4 3 2 1 

The two slices seem to be disconnected somehow. What exactly is going wrong here?

(p.s. I need a slice of pointers instead of a pointer to a slice for odd specific reasons in my project, including that the slice of pointers and the normal slice may not be the same length. If there's no way to achieve this I'm sure I could use a different method, however this seemed the most straightforward at first)


Solution

  • The range expression _, x := range x declares new variable x scoped to the loop. A slice element is assigned to x on each iteration of the loop. The loop

    for _, x := range x {
        g = append(g, &x)
    }
    

    appends the address of the loop variable x to the slice g.

    Use this code to append the address of the slice element to g:

    for i := range x {
        g = append(g, &x[i])
    }
    

    Note: The variable x declared in the question's loop shadows the slice variable x. The shadowing is not cause of the problem, but is poor practice.