Pointers

Pointers let a function reach back and change the caller's data instead of working on a copy. Go's pointers are far gentler than C's — no pointer arithmetic, garbage-collected memory — but the two operators & (address-of) and * (dereference) unlock efficient, mutable code. This lesson demystifies them once and for all.

Learn Pointers in our free Go course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.

Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Address-of & Dereference

Two operators do all the work. &x gives you the address of x — a value of type *int if x is an int . *p dereferences the pointer: it follows the address to read or write the value living there. Writing through a pointer changes the original variable — that's the whole point.

2️⃣ Pointers as Function Parameters

This is where pointers earn their keep. Go passes everything by value — a function receives a copy, so editing a plain parameter never touches the caller's variable. Pass a pointer instead and the function can modify the original by dereferencing it. Compare the two functions below: only the pointer version's change survives.

3️⃣ new, nil & Structs

The built-in new(T) allocates a zeroed T and returns a *T . Every pointer's zero value is nil , and dereferencing a nil pointer panics — so guard with a check when a pointer might be unset. A lovely convenience: with a pointer to a struct, Go lets you write p.Field and auto-dereferences for you — no need for the clunky (*p).Field .

Your turn — take an address, then write through the pointer.

Now pass an address so a function can reset your variable.

These lines change a variable through a pointer, but they're scrambled. Put them in order so the program prints 42 (assume a func main wraps them).

Why: x must exist before you can take its address. p := &x captures that address; *p = 42 writes through the pointer into x . Printing x last shows 42 because the write changed the original variable.

Predict the output before you reveal the answer.

8 — p points at x , so writing *p = 8 changes the original x to 8.

{'func f(n int) ; x := 4; f(x); fmt.Println(x)'}

4 — f takes n by value, so it edits a copy. The original x is unchanged. (Pass *int to mutate it.)

true — the zero value of any pointer type is nil . Dereferencing it would panic, so always check first.

Two main reasons: to let a function mutate the caller's value, and to avoid copying a large struct on every call. For small, read-only values, a plain value is clearer.

Much safer. There's no pointer arithmetic, memory is garbage-collected, and returning the address of a local variable is perfectly fine — Go keeps it alive for you.

Q: Why can I write p.Field instead of (*p).Field ?

Go automatically dereferences a struct pointer when you access a field or call a method, purely as a convenience. Both forms mean the same thing.

Write a deposit(a *Account, amount int) that adds to a.Balance , then call it with &acc . Because you pass the address, the change is visible in main . Write it yourself and match the example output.

Practice quiz

What does the & operator do in Go?

  • Dereferences a pointer
  • Takes the address of a variable
  • Multiplies values
  • Declares a pointer type

Answer: Takes the address of a variable. &x yields a pointer holding the memory address of x.

What does the * operator do when applied to a pointer value?

  • Takes its address
  • Dereferences it to read or write the pointed-to value
  • Frees memory
  • Compares pointers

Answer: Dereferences it to read or write the pointed-to value. *p dereferences the pointer to access the value it points to.

What is the zero value of a pointer?

  • 0
  • nil
  • An empty struct
  • Undefined

Answer: nil. An uninitialized pointer is nil.

What happens if you dereference a nil pointer?

  • Returns 0
  • Returns nil
  • Runtime panic
  • Compile error

Answer: Runtime panic. Dereferencing a nil pointer causes a runtime panic (invalid memory address).

After p := &x; *p = 20, what is the value of x?

  • 1
  • 20
  • 0
  • nil

Answer: 20. Writing through the pointer with *p = 20 changes the original variable x to 20.

How can a function modify the caller's variable?

  • Pass it by value
  • Take a *T parameter and call with &x
  • Return it only
  • Use a global

Answer: Take a *T parameter and call with &x. Pass a pointer (*T) and call with the address (&x) so the function mutates the original.

What does new(T) return?

  • A value of type T
  • A pointer to a zeroed T
  • nil
  • An error

Answer: A pointer to a zeroed T. new(T) allocates a zeroed T and returns a *T pointing to it.

Does Go support pointer arithmetic like C (p++)?

  • Yes
  • No
  • Only for slices
  • Only with unsafe

Answer: No. Ordinary Go has no pointer arithmetic — pointers can't be incremented.

Given p *Account, how do you read a struct field through it?

  • (*p).Field only
  • p.Field — Go auto-dereferences
  • p->Field
  • Field(p)

Answer: p.Field — Go auto-dereferences. Go auto-dereferences struct pointers, so p.Field works directly.

Passing a large struct by pointer instead of by value mainly avoids:

  • Type errors
  • Copying the whole struct
  • Imports
  • Panics

Answer: Copying the whole struct. A pointer passes an address, avoiding a full copy of the struct's data.