3

I am very new on golang. Here I have one question confused me a while. I know we should use "&" to get address, but what if we use printf on slice without "&"?

package main

import "fmt"

var slice = []int{1, 2, 3, 4}

func main() {

   fmt.Printf("address of slice %p \n", slice)

   fmt.Printf("address of slice %p \n", &slice)

}

The result is like this on my MacBook:

address of slice 0x11354d0

address of slice 0x1128be0

Thank you in advance!

icza
  • 389,944
  • 63
  • 907
  • 827
Jeffrey Yang
  • 41
  • 1
  • 6
  • I am no expert either but from what I understand from docs I think that if you use `%p slice`, it prints the address of 0th element (so maybe you can do some pointer arithmetic?!) and `%p &slice` prints the pointer of the slice including the "wrapper" or "overhead". I think you read the docs, I just want to make sure https://golang.org/pkg/fmt/ – Kyslik Sep 18 '18 at 06:44
  • just tried! thank you so much :-) – Jeffrey Yang Sep 18 '18 at 06:56
  • "I am very new on golang" so two advices: The language is called "Go" and always read the full documentation of a function including the package level documentation. Always. – Volker Sep 18 '18 at 07:10
  • thank you, Volker! – Jeffrey Yang Sep 18 '18 at 07:27

1 Answers1

11

Slices in Go are small, struct-like data structures, pointing to a backing array that actually holds the elements of the slice. Slice headers can be modeled with the type reflect.SliceHeader:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

Quoting from the package doc of fmt, the verb %p:

Printing:

The Verbs:

Slice:

%p    address of 0th element in base 16 notation, with leading 0x

Pointer:

%p    base 16 notation, with leading 0x
The %b, %d, %o, %x and %X verbs also work with pointers,
formatting the value exactly as if it were an integer.

So indeed, passing a slice value for the %p verb prints the address of the 0th element, which is the 0th element of the backing array, and when you pass &slice for %p, that will print the address of the slice header (because &slice is already a pointer value).

To verify, also print explicitly the address of the 0th element:

fmt.Printf("address of slice %p \n", slice)
fmt.Printf("address of slice %p \n", &slice)
fmt.Println(&slice[0])

Output will be (try it on the Go Playground):

address of slice 0x170460 
address of slice 0x17d0b8 
0x170460

As you can see, &slice[0] is the same value as %p for slice.

Now let's modify the example to use our own backing array:

var arr = [4]int{1, 2, 3, 4}
var slice = arr[:]

So this way we can also print the address of the 0th element of the backing array:

fmt.Printf("address of slice %p \n", slice)
fmt.Printf("address of slice %p \n", &slice)
fmt.Println(&slice[0])
fmt.Printf("Array 0th: %p", &arr[0])

Output (try it on the Go Playground):

address of slice 0x170460 
address of slice 0x183e78 
0x170460
Array 0th: 0x170460

And yes, the address of the 0th element of the backing array is indeed the same as the address of the 0th element of the slice, which is the same value printed for slice when passed for the %p verb.

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827