Go Cheatsheet

Pointers

Use this Go reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Basics

A pointer holds the memory address of a value. Go has pointers but no pointer arithmetic.

var p *int         // nil pointer to int
x := 42
p = &x             // & takes the address of x
fmt.Println(*p)    // * dereferences: prints 42
*p = 100           // modifies x through the pointer
fmt.Println(x)     // 100

Address-of and Dereference Operators

OperatorNameMeaning
&vaddress-ofreturns a pointer to v
*pdereferencethe value at address p
name := "Alice"
ptr := &name
*ptr = "Bob"
fmt.Println(name)  // "Bob"

Zero Value of a Pointer

The zero value of any pointer type is nil. Dereferencing a nil pointer panics.

var p *string     // nil
fmt.Println(p)    // <nil>
fmt.Println(*p)   // PANIC: runtime error: invalid memory address or nil pointer dereference

// Always guard
if p != nil {
    fmt.Println(*p)
}

new()

new(T) allocates zeroed storage for a T and returns *T. Equivalent to &T{} for structs.

p := new(int)         // *int pointing to 0
*p = 5

s := new(string)      // *string pointing to ""

// Equivalent
p2 := &int(0)         // not valid syntax
p3 := new(int)        // valid

Pointers to Structs

Auto-dereferencing: you do not need (*s).Field — Go allows s.Field through a pointer.

type Point struct{ X, Y int }

p := &Point{X: 1, Y: 2}
p.X = 10           // sugar for (*p).X = 10
fmt.Println(*p)    // {10 2}

Pointer Receivers vs Value Receivers

type Counter struct{ n int }

// Value receiver: operates on a copy
func (c Counter) Value() int { return c.n }

// Pointer receiver: modifies the original
func (c *Counter) Increment() { c.n++ }

c := Counter{}
c.Increment()      // Go auto-takes address: (&c).Increment()
c.Value()          // 1

Rule: if any method uses a pointer receiver, all methods on that type should use pointer receivers for consistency.

Pass by Value vs Pass by Pointer

Go is always pass-by-value. To mutate the caller's variable, pass a pointer.

func double(n int) {
    n *= 2  // only modifies the local copy
}

func doublePtr(n *int) {
    *n *= 2  // modifies the caller's variable
}

x := 5
double(x)           // x is still 5
doublePtr(&x)       // x is now 10

Pointers and Interfaces

An interface value holds a (type, value) pair. When calling a pointer-receiver method via an interface, you must pass a pointer.

type Incrementer interface{ Increment() }

type Counter struct{ n int }
func (c *Counter) Increment() { c.n++ }

var i Incrementer = &Counter{}  // OK: *Counter implements Incrementer
// var i Incrementer = Counter{} // COMPILE ERROR: Counter does not implement Incrementer

Pointer to Slice / Map

Slices and maps are already reference types (they contain internal pointers). You rarely need a pointer to them.

// This is unusual and seldom needed
func grow(s *[]int) {
    *s = append(*s, 1, 2, 3)
}

// Idiomatic: return the new slice
func grow(s []int) []int {
    return append(s, 1, 2, 3)
}

Pointers in Data Structures

// Linked list node
type Node struct {
    Val  int
    Next *Node
}

head := &Node{Val: 1, Next: &Node{Val: 2, Next: &Node{Val: 3}}}

// Binary tree
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

Optional Values with Pointers

Go has no built-in Option/Maybe. Use a pointer where nil means "absent".

type User struct {
    Name     string
    NickName *string   // nil if not set
}

nick := "gopher"
u := User{Name: "Alice", NickName: &nick}

if u.NickName != nil {
    fmt.Println(*u.NickName)
}

unsafe.Pointer

unsafe.Pointer bypasses Go's type system. Use only for interoperability with C or low-level memory tricks.

import "unsafe"

x := int64(42)
p := unsafe.Pointer(&x)
// Reinterpret as [8]byte
b := (*[8]byte)(p)
fmt.Println(b)

// uintptr: integer large enough to hold any address
// Convert: unsafe.Pointer → uintptr → arithmetic → unsafe.Pointer
// Never store a uintptr; GC may move the object underneath

Pointer Gotchas

// 1. Never dereference nil
var p *int
*p = 5  // PANIC

// 2. Returning a pointer to a local variable is SAFE in Go
// (unlike C — Go allocates on the heap when it escapes)
func newInt(n int) *int {
    x := n
    return &x  // safe: x escapes to heap
}

// 3. Pointer equality
a := 42
p1 := &a
p2 := &a
fmt.Println(p1 == p2)   // true (same address)

b := 42
p3 := &b
fmt.Println(p1 == p3)   // false (different vars, different addresses)

// 4. Cannot take address of map elements
m := map[string]int{"a": 1}
// p := &m["a"]  // COMPILE ERROR: cannot take address of map index

// 5. Interface nil vs typed nil
var err error       // nil interface
var p *MyError = nil
err = p             // non-nil interface wrapping nil *MyError
fmt.Println(err == nil)  // false! (common gotcha)