Lesson 26. A few pointers
After reading lesson 26, you’ll be able to
- Declare and use pointers
- Understand the relationship between pointers and random access memory (RAM)
- Know when to use—and not use—pointers
Walk around any neighborhood and you’ll likely encounter homes with individual addresses and street signs to guide you on your way. You may happen upon a closed-down shop with an apologetic sign: “Sorry, we’ve moved!” Pointers are a bit like the sign in the store window that directs you to a different address.

A pointer is a variable that points to the address of another variable. In computer science, pointers are a form of indirection, and indirection can be a powerful tool.
All problems in computer science can be solved by another level of indirection...
David Wheeler
Pointers are quite useful, but over the years they’ve been associated with a great deal of angst. Languages in the past—C in particular—had little emphasis on safety. Many crashes and security vulnerabilities can be tied back to the misuse of pointers. This gave rise to several languages that don’t expose pointers to programmers.
Go does have pointers, but with an emphasis on memory safety. Go isn’t plagued with issues like dangling pointers. This would be like heading to the address for your favorite shop, only to find it was accidentally replaced with the parking lot for a new casino.
If you’ve encountered pointers before, take a deep breath. This isn’t going to be so bad. If this is your first encounter, relax. Go is a safe place to learn pointers.
Consider this
Like the shop sign directing visitors to a new address, pointers direct a computer where to look for a value. What’s another situation where you’re directed to look somewhere else?
highlight, annotate, and bookmark
You can automatically highlight by performing the text selection while keeping the alt/ key pressed.

Pointers in Go adopt the well-established syntax used by C. There are two symbols to be aware of, the ampersand (&) and the asterisk (*), though the asterisk serves a dual purpose, as you’ll soon see.
The address operator, represented by an ampersand, determines the address of a variable in memory. Variables store their values in a computer’s RAM, and the location where a value is stored is known as its memory address. The following listing prints a memory address as a hexadecimal number, though the address on your computer will differ.
This is the location in memory where the computer stored 42. Thankfully, you can use the variable name answer to retrieve the value, rather than the memory address your computer uses.
Note
You can’t take the address of a literal string, number, or Boolean. The Go compiler will report an error for &42 or &"another level of indirection".
The address operator (&) provides the memory address of a value. The reverse operation is known as dereferencing, which provides the value that a memory address refers to. The following listing dereferences the address variable by prefixing it with an asterisk (*).
Listing 26.2. Dereference operator: memory.go
answer := 42 fmt.Println(&answer) #1 address := &answer fmt.Println(*address) #2
In the preceding listing and in figure 26.1, the address variable holds the memory address of answer. It doesn’t hold the answer (42), but it knows where to find it.
Note
Memory addresses in C can be manipulated with pointer arithmetic (for example address++), but Go disallows unsafe operations.
What does fmt.Println(*&answer) display for listing 26.2?
How might the Go compiler know the difference between dereferencing and multiplication?
Multiplication is an infix operator requiring two values, whereas dereferencing prefixes a single variable.
The address variable in listing 26.2 is a pointer of type *int, as the %T format verb reveals in the following listing.
Listing 26.3. A pointer type: type.go
answer := 42 address := &answer fmt.Printf("address is a %T\n", address) #1
The asterisk in *int denotes that the type is a pointer. In this case, it can point to other variables of type int.
Pointer types can appear anywhere types are used, including in variable declarations, function parameters, return types, structure field types, and so on. In the following listing, the asterisk (*) in the declaration of home indicates that it’s a pointer type.
Listing 26.4. Declaring a pointer: home.go
canada := "Canada" var home *string fmt.Printf("home is a %T\n", home) #1 home = &canada fmt.Println(*home) #2
Tip
An asterisk prefixing a type denotes a pointer type, whereas an asterisk prefixing a variable name is used to dereference the value that variable points to.
The home variable in the previous listing can point at any variable of type string. However, the Go compiler won’t allow home to point to a variable of any other type, such as int.
Note
The C type system is easily convinced that a memory address holds a different type. That can be useful at times but, once again, Go avoids potentially unsafe operations.
How can you distinguish between the declaration of a pointer type and dereferencing a pointer in listing 26.4?
An asterisk prefixing a type denotes a pointer type, whereas an asterisk prefixing a variable name is used to dereference the value that variable points to.
discuss

Charles Bolden became the administrator of NASA on July 17, 2009. He was preceded by Christopher Scolese. By representing the administrator role with a pointer, the following listing can point administrator at whoever fills the role (see figure 26.2).
Listing 26.5. Administrator for NASA: nasa.go
var administrator *string scolese := "Christopher J. Scolese" administrator = &scolese fmt.Println(*administrator) #1 bolden := "Charles F. Bolden" administrator = &bolden fmt.Println(*administrator) #2
Changes to the value of bolden can be made in one place, because the administrator variable points to bolden rather than storing a copy:
bolden = "Charles Frank Bolden Jr." fmt.Println(*administrator) #1
It’s also possible to dereference administrator to change the value of bolden indirectly:
*administrator = "Maj. Gen. Charles Frank Bolden Jr." fmt.Println(bolden) #1
Assigning major to administrator results in a new pointer that’s also pointing at the bolden string (see figure 26.3):
major := administrator *major = "Major General Charles Frank Bolden Jr." fmt.Println(bolden) #1
The major and administrator pointers both hold the same memory address and therefore are equal:
fmt.Println(administrator == major) #1
Charles Bolden was succeeded by Robert M. Lightfoot Jr. on January 20, 2017. After this change, administrator and major no longer point to the same memory address (see figure 26.4):
lightfoot := "Robert M. Lightfoot Jr." administrator = &lightfoot fmt.Println(administrator == major) #1
Assigning the dereferenced value of major to another variable makes a copy of the string. After the clone is made, direct and indirect modifications to bolden have no effect on the value of charles, or vice versa:
charles := *major *major = "Charles Bolden" fmt.Println(charles) #1 fmt.Println(bolden) #2
If two variables contain the same string, they’re considered equal, as with charles and bolden in the following code. This is the case even though they have different memory addresses:
charles = "Charles Bolden" fmt.Println(charles == bolden) #1 fmt.Println(&charles == &bolden) #2
In this section, the value of bolden was modified indirectly by dereferencing the administrator and major pointers. This demonstrates what pointers can do, though it would be straightforward to assign values directly to bolden in this instance.
What’s the benefit of using a pointer in listing 26.5?
Describe what the statements major := administrator and charles := *major do.
Changes can be made in one place, as the administrator variable points to a person rather than storing a copy.
The variable major is a new *string pointer that holds the same memory address as administrator, whereas charles is a string containing a copy of the value that major was pointing to.
Pointers are frequently used with structures. As such, the Go language designers chose to provide a few ergonomic amenities for pointers to structures.
Unlike strings and numbers, composite literals can be prefixed with an address operator. In the following listing, the timmy variable holds a memory address pointing to a person structure.
Listing 26.6. Person structure: struct.go
type person struct { name, superpower string age int } timmy := &person{ name: "Timothy", age: 10, }
Furthermore, it isn’t necessary to dereference structures to access their fields. The following listing is preferable to writing (*timmy).superpower.
Listing 26.7. Composite literals: struct.go
timmy.superpower = "flying" fmt.Printf("%+v\n", timmy) #1
What are valid uses of the address operator?
- Literal strings: &"Timothy"
- Literal integers: &10
- Composite literals: &person{name: "Timothy"}
- All of the above
What’s the difference between timmy.superpower and (*timmy).superpower?
The address operator is valid with variable names and composite literals, but not literal strings or numbers.
There’s no functional difference because Go automatically dereferences pointers for fields, but timmy.superpower is easier to read and is therefore preferable.
As with structures, composite literals for arrays can be prefixed with the address operator (&) to create a new pointer to an array. Arrays also provide automatic dereferencing, as shown in the following listing.
Listing 26.8. Pointer to an array: superpowers.go
superpowers := &[3]string{"flight", "invisibility", "super strength"} fmt.Println(superpowers[0]) #1 fmt.Println(superpowers[1:2]) #2
The array in the previous listing is dereferenced automatically when indexing or slicing it. There’s no need to write the more cumbersome (*superpowers)[0].
Note
Unlike the C language, arrays and pointers in Go are completely independent types.
Composite literals for slices and maps can also be prefixed with the address operator (&), but there’s no automatic dereferencing.
What’s another way to write (*superpowers)[2:] where superpowers is a pointer to an array?
Writing superpowers[2:] is the same, thanks to automatic dereferencing for arrays.
settings

Pointers are used to enable mutation across function and method boundaries.
Function and method parameters are passed by value in Go. That means functions always operate on a copy of passed arguments. When a pointer is passed to a function, the function receives a copy of the memory address. By dereferencing the memory address, a function can mutate the value a pointer points to.
In listing 26.9 a birthday function is declared with one parameter of type *person. This allows the function body to dereference the pointer and modify the value it points to. As with listing 26.7, it isn’t necessary to explicitly dereference the p variable to access the age field. The syntax in the following listing is preferable to (*p).age++.
Listing 26.9. Function parameters: birthday.go
type person struct { name, superpower string age int } func birthday(p *person) { p.age++ }
The birthday function requires the caller to pass a pointer to a person, as shown in the following listing.
Listing 26.10. Function arguments: birthday.go
rebecca := person{ name: "Rebecca", superpower: "imagination", age: 14, } birthday(&rebecca) fmt.Printf("%+v\n", rebecca) #1
What code would return Timothy 11? Refer to listing 26.6.
What age would Rebecca be if the birthday(p person) function didn’t use a pointer?
Rebecca would forever remain 14 if birthday didn’t utilize a pointer.
Method receivers are similar to parameters. The birthday method in the next listing uses a pointer for the receiver, which allows the method to mutate a person’s attributes. This behavior is just like the birthday function in listing 26.9.
Listing 26.11. Pointer receiver: method.go
type person struct { name string age int } func (p *person) birthday() { p.age++ }
In the following listing, declaring a pointer and calling the birthday method increments Terry’s age.
Listing 26.12. Method call with a pointer: method.go
terry := &person{ name: "Terry", age: 15, } terry.birthday() fmt.Printf("%+v\n", terry) #1
Alternatively, the method call in the next listing doesn’t use a pointer, yet it still works. Go will automatically determine the address of (&) a variable when calling methods with dot notation, so you don’t need to write (&nathan).birthday().
Listing 26.13. Method call without a pointer: method.go
nathan := person{ name: "Nathan", age: 17, } nathan.birthday() fmt.Printf("%+v\n", nathan) #1
Whether called with a pointer or not, the birthday method declared in listing 26.11 must specify a pointer receiver—otherwise, age wouldn’t increment.
Structures are frequently passed around with pointers. It makes sense for the birthday method to mutate a person’s attributes rather than create a whole new person. That said, not every structure should be mutated. The standard library provides a great example in the time package. The methods of the time.Time type never use a pointer receiver, preferring to return a new time instead, as shown in the next listing. After all, tomorrow is a new day.
Listing 26.14. Tomorrow is a new day: day.go
const layout = "Mon, Jan 2, 2006" day := time.Now() tomorrow := day.Add(24 * time.Hour) fmt.Println(day.Format(layout)) #1 fmt.Println(tomorrow.Format(layout)) #2
Tip
You should use pointer receivers consistently. If some methods need pointer receivers, use pointer receivers for all methods of the type (see golang.org/doc/faq#methods_on_values_or_pointers).
The code in listing 26.14 doesn’t reveal whether or not the Add method uses a pointer receiver because dot notation is the same either way. It’s best to look at the documentation for the methods of time.Time (see golang.org/pkg/time/#Time).
Go provides a handy feature called interior pointers, used to determine the memory address of a field inside of a structure. The levelUp function in the following listing mutates a stats structure and therefore requires a pointer.
Listing 26.15. The levelUp function: interior.go
type stats struct { level int endurance, health int } func levelUp(s *stats) { s.level++ s.endurance = 42 + (14 * s.level) s.health = 5 * s.endurance }
The address operator in Go can be used to point to a field within a structure, as shown in the next listing.
Listing 26.16. Interior pointers: interior.go
type character struct { name string stats stats } player := character{name: "Matthias"} levelUp(&player.stats) fmt.Printf("%+v\n", player.stats) #1
The character type doesn’t have any pointers in the structure definition, yet you can take the memory address of any field when the need arises. The code &player.stats provides a pointer to the interior of the structure.
A pointer that points at a field inside a structure. This is achieved by using the address operator on a field of a structure, such as &player.stats.
Though slices tend to be preferred over arrays, using arrays can be appropriate when there’s no need to change their length. The chessboard from lesson 16 is such an example. The following listing demonstrates how pointers allow functions to mutate elements of the array.
Listing 26.17. Resetting the chessboard: array.go
func reset(board *[8][8]rune) { board[0][0] = 'r' // ... } func main() { var board [8][8]rune reset(&board) fmt.Printf("%c", board[0][0]) #1 }
In lesson 20, the suggested implementation for Conway’s Game of Life makes use of slices even though the world is a fixed size. Armed with pointers, you could rewrite the Game of Life to use arrays.
Arrays are appropriate for data with fixed dimensions, such as a chess-board. Arrays are copied when passed to functions or methods unless a pointer is used, which enables mutation.
highlight, annotate, and bookmark
You can automatically highlight by performing the text selection while keeping the alt/ key pressed.

Not all mutations require explicit use of a pointer. Go uses pointers behind the scenes for some of the built-in collections.
Lesson 19 states that maps aren’t copied when assigned or passed as arguments. Maps are pointers in disguise, so pointing to a map is redundant. Don’t do this:
func demolish(planets *map[string]string) #1
It’s perfectly fine for the key or value of a map to be a pointer type, but there’s rarely a reason to point to a map.
Yes, even though maps don’t resemble pointers syntactically, they are in fact pointers. There’s no way to use a map that isn’t a pointer.
Lesson 17 describes a slice as a window into an array. To point at an element of the array, slices use a pointer.
A slice is represented internally as a structure with three elements: a pointer to an array, the capacity of the slice, and the length. The internal pointer allows the underlying data to be mutated when a slice is passed directly to a function or method.
An explicit pointer to a slice is only useful when modifying the slice itself: the length, capacity, or starting offset. In the following listing, the reclassify function modifies the length of the planets slice. The calling function (main) wouldn’t see this change if reclassify didn’t utilize a pointer.
Listing 26.18. Modifying a slice: slice.go
func reclassify(planets *[]string) { *planets = (*planets)[0:8] } func main() { planets := []string{ "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", } reclassify(&planets) fmt.Println(planets) #1 }
Instead of mutating the passed slice as in listing 26.18, an arguably cleaner approach is to write the reclassify function to return a new slice.
Functions and methods wanting to mutate the data they receive will require a pointer for which two data types?
discuss

The following listing demonstrates that both martian and a pointer to martian satisfy the talker interface.
Listing 26.19. Pointers and interfaces: martian.go
type talker interface { talk() string } func shout(t talker) { louder := strings.ToUpper(t.talk()) fmt.Println(louder) } type martian struct{} func (m martian) talk() string { return "nack nack" } func main() { shout(martian{}) #1 shout(&martian{}) #1 }
It’s different when methods use pointer receivers, as shown in the following listing.
Listing 26.20. Pointers and interfaces: interface.go
type laser int func (l *laser) talk() string { return strings.Repeat("pew ", int(*l)) } func main() { pew := laser(2) shout(&pew) #1 }
In the preceding listing, &pew is of type *laser, which satisfies the talker interface that shout requires. But shout(pew) doesn’t work because laser doesn’t satisfy the interface in this case.
A pointer to a value satisfies all the interfaces that the non-pointer version of the type satisfies.
settings

Take our tour and find out more about liveBook's features:
- Search - full text search of all our books
- Discussions - ask questions and interact with other readers in the discussion forum.
- Highlight, annotate, or bookmark.
Pointers can be useful, but they also add complexity. It can be more difficult to follow code when values could be changed from multiple places.
Use pointers when it makes sense, but don’t overuse them. Programming languages that don’t expose pointers often use them behind the scenes, such as when composing a class of several objects. With Go you decide when to use pointers and when to not use them.
- Pointers store memory addresses.
- The address operator (&) provides the memory address of a variable.
- A pointer can be dereferenced (*) to access or modify the value it points to.
- Pointers are types declared with a preceding asterisk, such as *int.
- Use pointers to mutate values across function and method boundaries.
- Pointers are most useful with structures and arrays.
- Maps and slices use pointers behind the scenes.
- Interior pointers can point at fields inside structures without declaring those fields as pointers.
- Use pointers when it makes sense but don’t overuse them.
Let’s see if you got this...
Write a program with a turtle that can move up, down, left, or right. The turtle should store an (x, y) location where positive values go down and to the right. Use methods to increment/decrement the appropriate variable. A main function should exercise the methods you’ve written and print the final location.
Tip
Method receivers will need to use pointers in order to manipulate the x and y values.