Notes — Module 5: Pointers¶
These are your personal study notes. Write freely and honestly. Incomplete notes are fine — they show where your understanding still needs work. Return to this file to add insights as they develop over time.
Module: [[go/5. Pointers]] Topic: [[go]] Date started: YYYY-MM-DD Status: In progress
Concept Map¶
Sketch how the concepts in this module relate to each other. Fill in the Mermaid diagram.
mindmap
root((Pointers))
Memory Model
variable has address
pointer holds an address
dereference = go to that address
Operators
& address-of
* dereference (type context)
* dereference (expression context)
Nil
zero value for all pointer types
nil dereference → runtime panic
always nil-guard before dereferencing
Call-by-Value
Go copies all arguments
pointer arg → shared access to original
value arg → independent copy
When to Use Pointers
mutation by callee
large structs (avoid copy cost)
optional / nullable (nil = absent)
shared identity
Allocation
new(T) → zeroed *T
&T{} → composite literal address
prefer &T{} for structs
Struct Pointer Convenience
p.Field auto-dereferences (*p).Field
used heavily with method receivers
Reference-Like Types
slice header = ptr + len + cap
map value = pointer to hash table
channel = pointer to runtime struct
append may replace underlying array
No Pointer Arithmetic
deliberate safety decision
unsafe package exists but rarely used
Escape Analysis
stack = lives only in function
heap = outlives function call
compiler decides automatically
returning &local is safe in Go
Double Pointer
**T for reassigning pointer itself
rare in idiomatic Go
Alternative: draw this on paper, photo it, and link the image here.
Key Insights¶
The "aha moments" — the things that, once understood, made the rest clear. Be specific: "I finally understood X because Y" is more useful than "X makes sense".
- Pointer = address, dereference = visit: I finally understood pointers when I pictured memory as a row of boxes. A pointer is a box that contains another box's number (address).
*pmeans "go to box numberp, read or write its contents." - Call-by-value is WHY pointers exist: Go always copies function arguments. Pointers are not a special feature — they are just values that happen to be addresses. Passing
&xgives the function a copy of x's address, which lets it reach back and modify x. - Add insights as you discover them
My Understanding¶
Explain the core concepts in your own words, as if teaching them to someone else. If you can't explain it simply, you don't understand it well enough yet.
What a pointer is¶
Your explanation here
What I'm still unsure about: (e.g., the exact definition of "addressable" — why can't you take &m["key"]?)
& and * operators¶
Your explanation here
What I'm still unsure about: (e.g., what happens if I do **p when p is *int)
Nil and nil-pointer panics¶
Your explanation here
What I'm still unsure about: (e.g., the difference between a nil pointer and an interface containing a nil pointer)
When to use pointers vs values¶
Your explanation here
What I'm still unsure about: (e.g., how large does a struct need to be before passing by pointer is worth it?)
Slices are already reference-like¶
Your explanation here
What I'm still unsure about: (e.g., exactly when does append reallocate vs reuse the existing array?)
Connections to Other Topics¶
How does this module connect to things you already know?
| This module's concept | Connects to | How |
|---|---|---|
| Pointer receivers (preview) | [[go/6. Methods and Interfaces]] | Methods with *T receivers use pointer semantics from this module; func (p *Counter) Increment() is syntactic sugar for a function that mutates through a pointer |
| Escape analysis (preview) | [[go/16. Performance and Profiling]] | The -gcflags='-m' flag shows which variables escape; heap allocations show up in pprof heap profiles; reducing unnecessary pointer escapes is a common optimization |
| Slice internals | [[go/4. Composite Types]] | A slice header is a struct with a pointer field; understanding slice-as-pointer explains why mutations propagate but append length changes do not |
| nil interface values | [[go/8. Error Handling]] | A nil *MyError wrapped in an error interface is not nil — this is a classic Go gotcha that connects pointer nil with interface nil |
Questions That Arose¶
Log questions as they appear. Don't stop to answer them now — just capture them. Then move the serious ones to QUESTIONS.md.
- Why can't you take the address of a map element (
&m["key"])? What would go wrong? → added to QUESTIONS.md as Q001 - When is using
*[]Tappropriate vs just returning a[]T? → might be answered in a later module - Does passing a pointer to a function always cause the pointed-to variable to escape to the heap? → added to QUESTIONS.md as Q002
Code Snippets Worth Remembering¶
Patterns, idioms, or examples that captured something important.
The fundamental pointer pattern¶
Why I'm saving this: This is the irreducible minimum. If this clicks, everything else follows.
The nil guard before dereference¶
func process(p *MyStruct) {
if p == nil {
return // always guard before dereferencing
}
p.Field = "something" // safe: p is not nil
}
Why I'm saving this: The nil guard is a mandatory reflex. Every function that receives a pointer should decide whether nil is valid and either handle or reject it explicitly.
&T{} preferred over new(T)¶
Why I'm saving this: &T{} is idiomatic, initializes in one expression, and is consistent with all composite type literals. new works but is rare in modern code.
Returning a pointer to a local variable (safe in Go)¶
func newPoint(x, y float64) *Point {
p := Point{X: x, Y: y} // p escapes to heap
return &p // safe: compiler handles it
}
Why I'm saving this: This is legal and idiomatic Go. In C this would be undefined behavior. The reminder prevents me from adding unnecessary indirection to avoid "returning local variable address."
What Tripped Me Up¶
Mistakes I made, misconceptions I had, things that confused me more than they should have. Being honest here helps you later.
- Struct mutation without a pointer — I initially wrote
func update(s MyStruct)and was confused why the original wasn't changing. The fix was always to use*MyStructand pass&sat the call site. - Map element address — I tried
p := &myMap["key"]and got a compile error. Maps can relocate their entries during growth; the address of a map element is not stable, so Go disallows taking it.
Summary in My Own Words¶
Write a 3–5 sentence summary of this entire module without looking at any notes. If you can't do this, you need more study time.
Write your summary here after completing the module.
Last updated: YYYY-MM-DD