Pointers
Every variable lives somewhere in memory, at an address. A pointer is a value that holds one of those addresses — it points at another variable instead of holding data directly.
Taking an address with &
The & operator ("address of") gives you a pointer to a variable. The type of
a pointer to an int is written *int — "pointer to int":
package main
import "fmt"
func main() {
x := 42
p := &x // p is a *int, holding the address of x
fmt.Println(p) // something like 0xc000012345
fmt.Println(*p) // 42
}
Printing p shows the address itself, which is rarely useful. What you almost
always want is the value it points at.
Following a pointer with *
The * operator ("dereference") follows a pointer to the variable it points at.
You can read through it, and — this is the important part — you can write
through it too:
package main
import "fmt"
func main() {
x := 42
p := &x
*p = 100 // write through the pointer, into x
fmt.Println(x) // 100
}
*p = 100 didn't touch p; it reached through p and changed x. That is the
whole point of pointers: sharing access to one variable in more than one place.
The zero value is nil
A pointer that points at nothing has the value nil. Dereferencing a nil
pointer is a runtime panic, so guard it when a pointer might be empty:
var p *int // nil — points nowhere
if p != nil {
fmt.Println(*p)
}
Why pointers matter: mutation across a call
Go passes arguments by value — a function receives a copy. So this function can't change the caller's variable:
func setToZero(n int) { n = 0 } // changes the copy, not the caller's variable
Pass a pointer instead, and the function can reach back through it to modify the original:
package main
import "fmt"
func setToZero(n *int) { *n = 0 }
func main() {
x := 5
setToZero(&x)
fmt.Println(x) // 0
}
When to use a pointer (and when not to)
Reach for a pointer when a function must mutate its caller's value, or when
you'd otherwise copy a large struct on every call. For small values you only
read — an int, a short string — pass them directly; a copy is cheap and
simpler to reason about.
No pointer arithmetic
If you've used C, note what's missing: you cannot do p + 1 to walk to the
next address. Go deliberately has no pointer arithmetic. A Go pointer either
points at a valid value or is nil — it can never drift off into arbitrary
memory. That single restriction removes a whole category of crashes and security
holes, and it's what lets Go's garbage collector safely track every pointer.
Practice
1. Double in Place
BeginnerImplement
doubleso it doubles theintits pointer argument points at, in place. It changes the caller's variable through the pointer and returns nothing:func double(n *int)For example:
x := 5 double(&x) // x is now 10Reach through the pointer with
*nto both read and write the value. Don't return anything — the whole job is done by mutating whatnpoints at.package main import "fmt" // double doubles the int that n points at, in place. func double(n *int) { // TODO: implement } func main() { x := 5 double(&x) fmt.Println(x) }Sign in to write and run your solution in the browser.
Sign in for hints and the solution.