Home > Mobile >  Passing pointer of string to a function leads to the wrong string being printed
Passing pointer of string to a function leads to the wrong string being printed

Time:01-23

I have the following program (simplified as much as possible):

package main

import "fmt"

type Test struct {
    Str *string
}

func main() {
    arr := []string{"vanC", "vanD"}

    arr2 := make([]Test, 0)
    for _, element := range arr {
        fmt.Println(element, &element)

        arr2 = append(arr2, Test{
            Str: &element,
        })
    }

    fn(arr2)
}

func fn(arr2 []Test) {
    for _, element := range arr2 {
        fmt.Println(*element.Str)
    }
}

Playground

As you can see, I am building a slice consisting of a struct containing a pointer to a string. I need this pointer to be able to pass nil as the strings are optional.

The output of this program is not at all what I am expecting.

Output:

vanC 0xc00009e220
vanD 0xc00009e220
vanD               // Why "vanD" here?
vanD

Expected:

vanC 0xc00009e220
vanD 0xc00009e220
vanC
vanD

I don't see any reason why vanD is printed twice and why vanC is not printed at all inside fn. Seeking an explanation and how to fix this.

CodePudding user response:

The loop variables are declared once, and overwritten at every iteration. You are adding the address of element, which remains fixed throughout the iteration, hence you add it twice. When you loop at the contents after the loop, what you see is two copies with the latest value.

You can add a copy to the slice:

for _, element := range arr {
        element:=element // Copy and redeclare
        fmt.Println(element, &element)

        arr2 = append(arr2, Test{
            Str: &element,
        })
    }

Or add it by its address in the slice:

for i, element := range arr {
        arr2 = append(arr2, Test{
            Str: &arr[i],
        })
    }
  •  Tags:  
  • go
  • Related