Skip to content
Lesson 13 of 14

Step 1 of 7 · Reading · ~4 min

Learn

Pointers and Errors

Pointers

A pointer is a value that holds the address of another variable. Go keeps the idea deliberately small — no pointer arithmetic, no manual freeing — and you reach for it for one everyday reason: letting a function change a variable that lives outside it.

Two operators: & and *

&x takes the address of the variable x and gives you a pointer. *p goes the other way — it dereferences the pointer, reading or writing the value stored at that address. The type of "pointer to an int" is spelled *int.

go

The & is not new. fmt.Scan(&x) has been handing Scan an address since Variables and Types, so it could write into your variable; that argument was a pointer all along.

Why functions need them

Go passes every argument by value, so a function works on a copy. A pointer parameter is how you opt out of that:

go

Two pointers, two writes, and a swap works the same way:

go

Now the trap that catches everyone once. Assigning to the parameter instead of through it compiles perfectly and does nothing:

go

a and b are themselves copies — copies of addresses. Rearranging them is invisible to the caller. Only a write through the * reaches the original.

Addresses of slice elements

You can take the address of a variable or of a slice element:

go

Things you can take the address of are called addressable: variables, slice elements, struct fields. A computed expression is not — &(a + b) does not compile. And remember from Loops that the value in for _, v := range scores is a copy of the element, so &v is the address of that copy, not of the slice.

nil pointers

The zero value of every pointer type is nil:

go

Dereferencing nil is a runtime panic, not a compile error, so check if r != nil whenever a pointer might be missing. What Go leaves out compared with C: p + 1 is a compile error (there is no pointer arithmetic), and there is nothing to call to release memory — the garbage collector reclaims it once nothing points there.

Common mistakes

  • Assigning to the parameter instead of through it. Like brokenSwap, a mutator whose body is n = &other rebinds only the function's own copy of the address. The caller's value never changes, so the program echoes its input back unchanged.
  • Pointing at a loop copy. for _, v := range nums hands you a fresh copy each pass; writes through &v land in that copy and are thrown away at the end of the iteration. Index the slice — &nums[i] — when you mean to touch the real element.
  • Printing inside the mutator. A function that takes a *int to modify it should modify it and nothing else. If it prints too, every value shows up twice in the output.
  • Treating the pointer as a number. n++ or n = n + 1 where n is a *int is a compile error: a pointer is not arithmetic in Go, and the ++ belongs somewhere else.

Your exercise

Fill in increment so the int its argument points at ends up one larger. The starter already parses the input, calls increment once per number with that element's address, and prints the results — only the function body is missing. The likeliest mistake is writing to the parameter rather than through it: it compiles, and your output is the input unchanged.

Up nextMultiple Returns and the error PatternPointers and Errors

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…