Print pointer to integer slice

I noticed that when printing pointer that points to a primitive (like integer) it output hexacdemic type memory address for that integer. but for pointer that points to a complicated structure like slice/struct…it prints &slice and I have to use `fmt.Printf("%p", pointer) in order to print address. so what’s the difference of printing pointer that point to a primitive vs slice/struct…below is the code example

package main

import "fmt"

func main() {
	a := 1
	pa := &a

	b := []int{1, 2, 3}
	pb := &b

	fmt.Println(a, "\t", pa, "\n")
	fmt.Println(b, "\t", pb, "\n")
	fmt.Printf("%p\n", pb)
}

here is the output:

1        0xc000096000 

[1 2 3]          &[1 2 3] 

0xc000098000

Thanks

2 Likes

I think you got confused with pointer object (e.g. pa, with pointer &a) and the format used to printout the data. There are no differences. Consider the amended codes with struct and tidy and uniformed printout.

package main

import "fmt"

func main() {
	a := 1
	pa := &a
	b := []int{1, 2, 3}
	pb := &b
	
	c := struct{
	  id int
	}{
	  id: 2,
	}
	pc := &c
	
	fmt.Printf("Name:a  | Type:%-20T | Pointer:%-20p | Value:%v\n", a, &a, a)
	fmt.Printf("Name:pa | Type:%-20T | Pointer:%-20p | Value:%p\n", pa, &pa, pa)
	fmt.Printf("Name:b  | Type:%-20T | Pointer:%-20p | Value:%v\n", b, &b, b)
	fmt.Printf("Name:pb | Type:%-20T | Pointer:%-20p | Value:%p\n", pb, &pb, pb)
	fmt.Printf("Name:c  | Type:%-20T | Pointer:%-20p | Value:%v\n", c, &c, c)
	fmt.Printf("Name:pc | Type:%-20T | Pointer:%-20p | Value:%p\n", pc, &pc, pc)
}

This will output:

Name:a  | Type:int                  | Pointer:0x414020             | Value:1
Name:pa | Type:*int                 | Pointer:0x40c138             | Value:0x414020
Name:b  | Type:[]int                | Pointer:0x40a0e0             | Value:[1 2 3]
Name:pb | Type:*[]int               | Pointer:0x40c140             | Value:0x40a0e0
Name:c  | Type:struct { id int }    | Pointer:0x414030             | Value:{2}
Name:pc | Type:*struct { id int }   | Pointer:0x40c148             | Value:0x414030

Program exited.

Basic Object and Memory

Whenever you create a variable, you literally created an object of type allocated on memory. Example:

  1. a is type int, an integer object, with memory pointing at 0x414020, holding value 1.
  2. pa is type int*, an integer pointer object, with memory pointing at 0x40c138, holding value of 0x414020 which is pointer of a.

Obtaining an Object’s Pointer

There is only one way to obtain any established object: using the & prefix symbol. So, to obtain the memory pointer of:

  1. a, you use &a.
  2. pa, you use &pa.

Printing Pointer

The correct format of printing pointer is always and strictly %p. This includes printing object pointer’s value that holds pointer of another object (e.g. pa with %p instead of the debugging version %v).

NOTE: In the example above, I style it to always use up 20 columns for pretty printing the output so it was transforms from %p to %-20p.

Why do we Use Pointers

So that we manage data at one memory location and also keeping function as function. By default, if the parameter is not a pointer (pass by pointer), the function actually clones the variable instead (pass by value). Here is an animation about the pointer:

pass-by-reference-vs-pass-by-value-animation
Notice that fillCup is now behaving exactly like a function, altering the dataset we gave to it.

More read up: Pass by reference vs pass by value

Slice & Struct

They are still treated as an objects just like others. However, one thing about slice is that slice itself is a “container” of pointers pointing to a bunch of memories location that formulates its “dynamic arrays” capabilities (See Slice Internal: Go Slices: usage and internals - The Go Programming Language). Hence, operating on slice is like operating onto a list of pointers by its own nature.

Hence, if you track the history of slice, there was a (very long) discussion about whether to use slice pointer or slice as function parameters. That’s another long story.

3 Likes

wow, you’re an author! and thanks for such detailed and animated response!

So, my take away is always use fmt.Printf + %p to print pointer, right?

2 Likes

yes.

1 Like

“mark as solved”?

1 Like

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