Hackerman's Hacking Tutorials

The knowledge of anything, since all things have causes, is not acquired or complete unless it is known by its causes. - Avicenna

Nov 18, 2018 - 2 minute read - Comments - Go

Pointers Inside for

Do not directly assign the for counter/range variables to a slice as pointers. Read this by Jon Calhoun Variables declared in for loops are passed by reference. “[…] the variables aren’t being redeclared with each iteration […]“.

I have written so much buggy code that I am going to write this down.

Here’s a sample program to reproduce it. In this case, we are creating a slice of int pointers, then assigning items in a for loop. The expectation is that it will contain references to 0-9 but it’s not. i is not redeclared after each iteration, it’s the same variable and we are storing a pointer to it in each iteration regardless of value. Run it on Go playground https://play.golang.org/p/EyS0KwWxf9g

package main

import "fmt"

func main() {
    // Create a slice of int pointers.
	var pInt []*int

    // Assign items in a counter.
	for i := 0; i < 10; i++ {
		pInt = append(pInt, &i)
	}

    // Print the slice.
	fmt.Println(pInt)
    
    // Print the values.
	for _, i := range pInt {
		fmt.Printf("%v ", *i)
	}
}

And the result is:

[0x416020 0x416020 0x416020 0x416020 0x416020 0x416020 0x416020 0x416020 0x416020 0x416020]
10 10 10 10 10 10 10 10 10 10 

This happens a lot when I am reading items from a slice with range and then appending them to another slice. The solution is simple, create a variable inside the for and then assign a pointer from that. Run it on Go playground https://play.golang.org/p/jDg8ruAtdA_r

package main

import "fmt"

func main() {
    // Create a slice of int pointers.
	var pInt []*int

    // Assign items in a counter.
	for i := 0; i < 10; i++ {
		// Temp variable.
		tempInt := i
		pInt = append(pInt, &tempInt)
	}

    // Print the slice.
	fmt.Println(pInt)
    
    // Print the values.
	for _, i := range pInt {
		fmt.Printf("%v ", *i)
	}
}

And it works:

[0x416020 0x416024 0x416028 0x41602c 0x416030 0x416034 0x416038 0x41603c 0x416040 0x416044]
0 1 2 3 4 5 6 7 8 9