0
0
Goprogramming~15 mins

Address and dereference operators in Go - Deep Dive

Choose your learning style9 modes available
Overview - Address and dereference operators
What is it?
In Go, the address operator (&) gives you the memory location of a variable, called a pointer. The dereference operator (*) lets you access or change the value stored at that memory location. Together, they allow you to work directly with memory addresses instead of just values.
Why it matters
Without these operators, you could only work with copies of data, which can be inefficient or impossible for some tasks like modifying data inside functions or managing large data structures. Using pointers with address and dereference operators lets programs be faster and use memory more wisely.
Where it fits
Before learning this, you should understand variables, types, and basic assignment in Go. After this, you can learn about pointer types, pointer arithmetic (limited in Go), and advanced topics like structs, slices, and interfaces that often use pointers.
Mental Model
Core Idea
The address operator gets where a value lives in memory, and the dereference operator lets you reach inside that place to read or change the value.
Think of it like...
Imagine a house address written on a letter (&). The address tells you where the house is. The dereference (*) is like going to that house and opening the door to see or change what's inside.
Variable x holds a value
  ┌─────────────┐
  │  x = 42     │
  └─────────────┘

&x gives the address of x
  ┌─────────────┐
  │ &x = 0x1234 │  <-- memory location
  └─────────────┘

*p points to the value at address
  ┌─────────────┐
  │ *p = 42     │  (value at 0x1234)
  └─────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding variables and memory
🤔
Concept: Variables store values in memory locations identified by addresses.
In Go, when you declare a variable like var x int = 42, the computer stores 42 somewhere in memory and remembers where. This location has an address, but normally you just use the variable name to get or set the value.
Result
You can store and retrieve values using variable names, but you don't see or use the memory address directly yet.
Knowing that variables have memory addresses sets the stage for understanding pointers and how to access those addresses.
2
FoundationUsing the address operator (&)
🤔
Concept: The & operator gets the memory address of a variable.
If you write p := &x, you get the address where x is stored. Now p is a pointer holding that address, not the value 42 itself. This means p points to x's location in memory.
Result
You have a pointer variable p that stores the address of x, allowing indirect access to x.
Understanding & lets you move from values to their locations, which is key for pointers.
3
IntermediateDereferencing pointers with *
🤔Before reading on: do you think *p gives you the address stored in p or the value at that address? Commit to your answer.
Concept: The * operator accesses the value stored at the pointer's address.
If p holds the address of x, then *p means 'go to that address and get the value there.' For example, if p := &x, then *p is the same as x. You can also assign *p = 100 to change x's value through the pointer.
Result
Using *p reads or changes the value at the memory location p points to, effectively accessing x indirectly.
Knowing * lets you work with the actual data behind a pointer, enabling indirect manipulation.
4
IntermediatePointers and function arguments
🤔Before reading on: do you think passing a pointer to a function allows it to modify the original variable or just a copy? Commit to your answer.
Concept: Passing pointers to functions lets those functions change the original variable's value.
When you pass a variable to a function normally, Go copies the value. Changes inside the function don't affect the original. But if you pass a pointer (like *int), the function can dereference it and change the original variable's value.
Result
Functions can modify variables outside their own scope by using pointers.
Understanding this explains why pointers are essential for modifying data in functions and for efficient memory use.
5
IntermediatePointer types and nil pointers
🤔
Concept: Pointers have types and can be nil, meaning they point to nothing.
A pointer's type shows what kind of value it points to, like *int or *string. If a pointer is nil, it doesn't point anywhere valid. Trying to dereference a nil pointer causes a runtime error (panic). Always check pointers before dereferencing.
Result
You learn to handle pointers safely and understand their types.
Recognizing pointer types and nil values prevents common bugs and crashes.
6
AdvancedPointer arithmetic limitations in Go
🤔Before reading on: do you think Go allows adding numbers to pointers like C does? Commit to your answer.
Concept: Go does not support pointer arithmetic to keep safety and simplicity.
Unlike languages like C, Go forbids adding or subtracting numbers from pointers. This avoids unsafe memory access and bugs. Instead, Go encourages using slices and arrays with indexing for safe access.
Result
You understand Go's design choice to prioritize safety over pointer math.
Knowing this helps you avoid unsafe patterns and use Go's safer alternatives.
7
ExpertHow Go manages pointers and garbage collection
🤔Before reading on: do you think Go pointers can cause memory leaks like in manual memory management languages? Commit to your answer.
Concept: Go uses garbage collection to manage memory, so pointers don't require manual freeing.
Go's runtime tracks pointers and automatically frees memory no longer in use. This means you don't manually allocate or free memory like in C. However, careless pointer use can still cause memory to stay allocated longer than needed (memory leaks).
Result
You see how Go balances pointer use with automatic memory management.
Understanding Go's garbage collection clarifies how pointers work safely and efficiently in production.
Under the Hood
When you use the & operator, Go finds the memory address where the variable's value is stored and returns it as a pointer. The * operator takes a pointer and accesses the memory at that address to read or write the value. Internally, pointers are just memory addresses stored as values. Go's runtime tracks these pointers for garbage collection, ensuring memory safety without manual freeing.
Why designed this way?
Go was designed to be simple and safe. Allowing pointers gives control over memory and performance, but Go restricts unsafe pointer arithmetic to avoid common bugs. Automatic garbage collection removes the burden of manual memory management, making pointers safer and easier to use than in older languages like C.
┌─────────────┐       ┌───────────────┐       ┌───────────────┐
│ Variable x  │       │ Pointer p     │       │ Memory        │
│ Value: 42   │       │ Value: 0x1234│──────▶│ Address 0x1234│
│ Address:0x1234│      │ Type: *int   │       │ Value: 42     │
└─────────────┘       └───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does *p give you the address stored in p or the value at that address? Commit to your answer.
Common Belief:Many think *p returns the address stored in p.
Tap to reveal reality
Reality:*p returns the value stored at the address p points to, not the address itself.
Why it matters:Confusing this leads to bugs where code tries to use *p as an address, causing errors or crashes.
Quick: Can you do pointer arithmetic like adding 1 to a pointer in Go? Commit to yes or no.
Common Belief:Some believe Go supports pointer arithmetic like C or C++.
Tap to reveal reality
Reality:Go does not allow pointer arithmetic to keep programs safe and simple.
Why it matters:Trying to do pointer math in Go causes compile errors and forces developers to use safer alternatives.
Quick: Does passing a variable to a function always allow the function to change the original variable? Commit to yes or no.
Common Belief:Many think passing a variable to a function lets it modify the original variable.
Tap to reveal reality
Reality:Passing a variable copies its value; only passing a pointer lets the function modify the original variable.
Why it matters:Misunderstanding this causes bugs where changes inside functions don't affect the original data.
Quick: Can Go pointers cause memory leaks like in C? Commit to yes or no.
Common Belief:Some think Go pointers can cause memory leaks because they manage memory manually.
Tap to reveal reality
Reality:Go uses garbage collection, so pointers don't require manual freeing, reducing memory leak risks.
Why it matters:Knowing this helps developers trust Go's memory safety and focus on writing correct pointer logic.
Expert Zone
1
Pointers in Go can point to local variables safely because the compiler escapes them to the heap when needed.
2
Using pointers with interfaces can be subtle because method sets differ between pointer and value receivers.
3
The zero value of a pointer is nil, which is safe to compare but unsafe to dereference without checking.
When NOT to use
Avoid using pointers when you only need to read data without modification; passing values is simpler and safer. Also, avoid pointers for small structs where copying is cheaper. For shared mutable state, consider channels or sync primitives instead of raw pointers.
Production Patterns
In real Go code, pointers are used to modify structs inside functions, implement methods with pointer receivers for efficiency, and manage large data structures without copying. Nil pointers are often used to represent optional values or errors. Careful nil checks and pointer usage patterns prevent runtime panics.
Connections
References in C++
Similar concept of indirect access to variables, but C++ references are safer aliases without explicit dereferencing.
Understanding Go pointers clarifies how indirect access works differently across languages and why Go requires explicit dereferencing.
Memory addresses in computer architecture
Pointers directly represent memory addresses, linking programming concepts to hardware memory layout.
Knowing how memory addresses work at hardware level deepens understanding of pointers and their role in efficient computing.
Linked data structures in data science
Pointers enable building linked lists, trees, and graphs by connecting nodes via addresses.
Recognizing pointers as links helps grasp complex data structures used in algorithms and data science.
Common Pitfalls
#1Dereferencing a nil pointer causing a runtime panic.
Wrong approach:var p *int fmt.Println(*p) // panic: runtime error: invalid memory address or nil pointer dereference
Correct approach:var p *int if p != nil { fmt.Println(*p) } else { fmt.Println("Pointer is nil") }
Root cause:Not checking if a pointer is nil before dereferencing leads to crashes.
#2Expecting function to modify original variable without using pointers.
Wrong approach:func change(x int) { x = 100 } var a = 42 change(a) fmt.Println(a) // prints 42, not 100
Correct approach:func change(x *int) { *x = 100 } var a = 42 change(&a) fmt.Println(a) // prints 100
Root cause:Passing by value copies data; only passing pointer allows modification of original.
#3Trying to do pointer arithmetic in Go.
Wrong approach:var arr = []int{1,2,3} p := &arr[0] p = p + 1 // compile error: invalid operation
Correct approach:var arr = []int{1,2,3} p := &arr[1] // get pointer to second element directly
Root cause:Go disallows pointer arithmetic to maintain safety and simplicity.
Key Takeaways
The & operator gets the memory address of a variable, creating a pointer to it.
The * operator dereferences a pointer to access or modify the value at that memory address.
Pointers allow functions to modify variables outside their scope and enable efficient memory use.
Go restricts pointer arithmetic to keep programs safe and uses garbage collection to manage memory automatically.
Always check pointers for nil before dereferencing to avoid runtime errors.