Understanding use of pointers to structure in method implementation

Hi,

I am not an experienced programmer and I am newbie to Go. I was trying to interiorize the pointer concept. To do so I made the following test:

package main

import (
	"fmt"

	"xpckg"
)


func main() {


	s := new(xpckg.MyType)
	
	fmt.Println("&s in main:", &s, "\ns in main:", s,"\n*s in main:", *s, "\ns.Test in main:", s.Test,  "\n&s.Test in main:", &s.Test, "\n")

	s.Callxpckg()

	s.Field1 = 2
	s.Test = "In main"

	fmt.Println("&s in main:", &s, "\ns in main:", s,"\n*s in main:", *s, "\ns.Test in main:", s.Test,  "\n&s.Test in main:", &s.Test, "\n")

}
package xpckg

import (
	"fmt"
)

type MyType struct {
	Field1 int
	Test string
}


func (s *MyType) Callxpckg() {

	s.setFields()

	fmt.Println("&s in Callxpckg:", &s, "\ns in Callxpckg:", s, "\n*s in Callxpckg:", *s, "\ns.Test in Callxpckg:", s.Test,  "\n&s.Test in Callxpckg:", &s.Test, "\n")

}

func (s *MyType) setFields() {

	s.Field1 = 1
	s.Test = "Inside pckg"

	fmt.Println("&s in setFields:", &s,"\ns in setFields:", s, "\n*s in setFields:", *s, "\ns.Test in setFields:", s.Test,  "\n&s.Test in setFields:", &s.Test, "\n")

}

And received the following answer:


&s in main: 0xc042052018
s in main: &{0 }
*s in main: {0 }
s.Test in main:
&s.Test in main: 0xc042040408

&s in setFields: 0xc042052030
s in setFields: &{1 Inside pckg}
*s in setFields: {1 Inside pckg}
s.Test in setFields: Inside pckg
&s.Test in setFields: 0xc042040408

&s in Callxpckg: 0xc042052028
s in Callxpckg: &{1 Inside pckg}
*s in Callxpckg: {1 Inside pckg}
s.Test in Callxpckg: Inside pckg
&s.Test in Callxpckg: 0xc042040408

&s in main: 0xc042052018
s in main: &{2 In main}
*s in main: {2 In main}
s.Test in main: In main
&s.Test in main: 0xc042040408


I was expecting that the address stored in pointer to myType (s) would be the same, however I could not check this given that cmd retrieves &{0 }, is there a reason for this?
I understand why the address of the variables s (&s) that store the address to myType are different.
However I cannot understand why s.Test have the same address (&s.Test) in all places given that &s does not have the same address in all functions? For the same reason as &s stores different values shouldn’t this store different values too? On the other end I didn’t defined Test as a pointer to a string rather I defined it as string so it also make sense that &s.Test retrieves the address of the variable and not the address of the address.

I am a bit puzzled? Can somebody provide help understanding this? Either by value or by reference.

Thank you.

Can you add code tags (triple backticks) above and below your code? As is it’s fairly unreadable.

```
code
code
```

Sorry I got the wrong char. I’ve just edited the original post. Thank you.

You are being a little bit tricked by fmt.Println being helpful. Here

s := new(xpckg.MyType)

you are declaring a new pointer s, allocating an xpckg.MyType, and storing the pointer to it in s. Then you print some stuff. However what you print might not be what you think you print.

fmt.Println(&s) // (0xc042052018)

This is the address of s. Not the address in s, but the address of the pointer variable itself.

fmt.Println(s) // &{0 }

You’re asking Println to print a pointer. It helpfully follows it and prints the value ({0 }) and prepends an ampersand to show that it was a pointer it followed.

fmt.Println(*s) // {0 }

You’re derefering the pointer yourself. No surprises here.

To print the pointer value, use Printf with the %p verb:

fmt.Printf("s points to %p\n", s)
1 Like

I was a little too slow :frowning:

Anyway, I modified the code to print things out nicely:

package main

import (
	"log"

	"xpckg"
)

func main() {
	log.SetFlags(log.Lshortfile)

	s := new(xpckg.MyType)

	log.Printf("\n&s\t%p\ns\t%p\n*s\t%p\ns.Test\t%p\n&s.Test\t%p\n\n", &s, s, *s, s.Test, &s.Test)

	s.Callxpckg()

	s.Field1 = 2
	s.Test = "In main"

	log.Printf("\n&s\t%p\ns\t%p\n*s\t%p\ns.Test\t%p\n&s.Test\t%p\n\n", &s, s, *s, s.Test, &s.Test)
} 
package xpckg

import "log"

type MyType struct {
	Field1 int
	Test   string
}

func (s *MyType) Callxpckg() {
	s.setFields()

	log.Printf("\n&s\t%p\ns\t%p\n*s\t%p\ns.Test\t%p\n&s.Test\t%p\n\n", &s, s, *s, s.Test, &s.Test)
}

func (s *MyType) setFields() {
	s.Field1 = 1
	s.Test = "Inside pckg"

	log.Printf("\n&s\t%p\ns\t%p\n*s\t%p\ns.Test\t%p\n&s.Test\t%p\n\n", &s, s, *s, s.Test, &s.Test)
}

resulting in this output:

main.go:14:
&s	0xc42000c028
s	0xc42000a2e0
*s	%!p(xpckg.MyType={0 })
s.Test	%!p(string=)
&s.Test	0xc42000a2e8

xpckg.go:20:
&s	0xc42000c040
s	0xc42000a2e0
*s	%!p(xpckg.MyType={1 Inside pckg})
s.Test	%!p(string=Inside pckg)
&s.Test	0xc42000a2e8

xpckg.go:13:
&s	0xc42000c038
s	0xc42000a2e0
*s	%!p(xpckg.MyType={1 Inside pckg})
s.Test	%!p(string=Inside pckg)
&s.Test	0xc42000a2e8

main.go:21:
&s	0xc42000c028
s	0xc42000a2e0
*s	%!p(xpckg.MyType={2 In main})
s.Test	%!p(string=In main)
&s.Test	0xc42000a2e8

s.Test always has the same address because it is always the same string.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.