🏠 Pointers and Memory in Go: Your Home Address Adventure!
Imagine you have a house. Your house has stuff inside (like toys, books, games). But your house also has an address — the street number that tells the mailman where to find you!
In Go, pointers work just like home addresses. Instead of carrying your whole house around, you just share the address. Simple, right?
🎯 What We’ll Explore
- Pointer Basics — What’s an address in computer land?
- Pointer Operations — Getting and using addresses
- nil Pointer — When there’s no address yet
- new Function — Building a new house instantly
- Addressability Rules — What can have an address?
- Value vs Reference — Copying the house vs sharing the address
1️⃣ Pointer Basics — Understanding Addresses
The Big Idea
A pointer is just an address. It tells Go: “Hey, the thing you want lives over THERE!”
Real Life Example
Your friend asks: "Where's your toy box?"
Option 1: You carry the WHOLE toy box to them (heavy!)
Option 2: You tell them "It's in my room, shelf 3" (easy!)
Option 2 is a pointer — you shared the location, not the thing itself!
In Go Code
age := 10 // A variable (the toy box)
ptr := &age // A pointer (the address)
fmt.Println(age) // Prints: 10
fmt.Println(ptr) // Prints: 0xc0000... (an address!)
Key Symbol: *
The * symbol means “pointer to something.”
var p *int // p is a pointer to an integer
// (p will hold an ADDRESS where an int lives)
Think of *int as: “This is a sticky note that has a house address written on it, and at that house lives a number!”
2️⃣ Pointer Operations — The Two Magic Symbols
Meet & and *
| Symbol | What It Does | Memory Trick |
|---|---|---|
& |
“Give me the ADDRESS of this thing” | Ampersand = Address |
* |
“Go TO this address and get the thing” | Star = “Go far” to find it |
Getting an Address with &
score := 100
address := &score // & gives us the address
fmt.Println(address) // 0xc000018030 (some memory location)
Reading What’s at an Address with *
score := 100
address := &score
value := *address // * means "look inside this address"
fmt.Println(value) // Prints: 100
Changing What’s at an Address
Here’s the magic — you can change the original value through its pointer!
cookies := 5
ptr := &cookies
*ptr = 10 // Go to that address, change the value!
fmt.Println(cookies) // Prints: 10 (it changed!)
Story Time: The Cookie Jar
You have a cookie jar with 5 cookies.
You give your friend a map to the cookie jar.
Your friend follows the map and adds 5 more cookies.
Now when YOU look at the jar — surprise! 10 cookies!
Both you and your friend were looking at the same jar, not copies!
3️⃣ nil Pointer — The Empty Address
What is nil?
nil means “no address” or “pointing to nothing.”
It’s like having a blank sticky note — you haven’t written any address on it yet!
var ptr *int // Declared but not assigned
fmt.Println(ptr) // Prints: <nil>
⚠️ Danger Zone!
If you try to use a nil pointer, Go will crash!
var ptr *int // ptr is nil
*ptr = 42 // CRASH! There's no address to go to!
Safe Pointer Usage
Always check if a pointer is nil before using it:
var ptr *int
if ptr != nil {
fmt.Println(*ptr)
} else {
fmt.Println("Pointer is empty!")
}
Think of it Like This
Trying to visit a nil pointer is like:
"Go to the house at address ____"
"But... there's no address written here!"
4️⃣ The new Function — Instant House Builder
What Does new() Do?
The new() function:
- Creates space in memory for a value
- Sets that space to zero (empty)
- Gives you the address of that space
ptr := new(int) // Creates an int, gives you its address
fmt.Println(*ptr) // Prints: 0 (the default "zero" value)
*ptr = 42 // Now put 42 at that address
fmt.Println(*ptr) // Prints: 42
new() vs Regular Variables
// Method 1: Regular way
x := 0
ptr1 := &x
// Method 2: Using new()
ptr2 := new(int) // Same result, but x doesn't exist as a name
When to Use new()
Use new() when you need a pointer right away but don’t need a named variable:
// Creating a pointer to a struct
person := new(Person)
person.Name = "Alex"
person.Age = 10
5️⃣ Addressability Rules — What CAN Have an Address?
Not everything in Go can have its address taken! Let’s learn the rules.
✅ CAN Take Address Of:
| Thing | Example | Why |
|---|---|---|
| Variables | &myVar |
They have a home in memory |
| Struct fields | &person.Name |
Part of a variable |
| Array elements | &arr[0] |
They’re stored somewhere |
| Slice elements | &slice[2] |
Points to backing array |
❌ CANNOT Take Address Of:
| Thing | Example | Why Not |
|---|---|---|
| Constants | &100 |
They’re not stored anywhere specific |
| Literals | &"hello" |
Same reason |
| Function results | &getName() |
Result is temporary |
| Map values | &myMap["key"] |
Maps can move things around! |
Code Examples
// ✅ This works
name := "Go"
ptr := &name
// ❌ This fails
// ptr := &"Hello" // Can't take address of a literal!
// ❌ This fails too
myMap := map[string]int{"score": 100}
// ptr := &myMap["score"] // Can't take address of map value!
The Rule in Simple Words
If something has a permanent home in memory, you can get its address. If it’s temporary or might move, you can’t!
6️⃣ Value vs Reference Semantics — The Big Choice
This is the most important concept! Let’s master it.
Value Semantics: Making Copies
When you pass a variable normally, Go makes a copy:
func double(n int) {
n = n * 2 // Only changes the copy!
}
func main() {
num := 5
double(num)
fmt.Println(num) // Still 5! The original didn't change.
}
Reference Semantics: Sharing the Address
When you pass a pointer, you share the original:
func double(n *int) {
*n = *n * 2 // Changes the original!
}
func main() {
num := 5
double(&num)
fmt.Println(num) // Now 10! The original changed.
}
The Pizza Story 🍕
VALUE SEMANTICS:
You have a pizza recipe. You give your friend a COPY.
They add extra cheese to THEIR copy.
Your recipe stays the same!
REFERENCE SEMANTICS:
You share the ACTUAL recipe card with your friend.
They add extra cheese to it.
Now YOUR recipe also has extra cheese!
When to Use Each?
| Use Value (Copy) When… | Use Reference (Pointer) When… |
|---|---|
| Data is small (int, bool) | Data is large (big structs) |
| You want safety from changes | You need to modify the original |
| You want predictable behavior | You want to save memory |
Visual Flow
graph TD A["Function Call"] --> B{What to Pass?} B -->|Small data, don't modify| C["Pass by Value"] B -->|Large data or need to modify| D["Pass by Pointer"] C --> E["Safe copy created"] D --> F["Original data shared"]
🎯 Quick Summary
| Concept | What It Is | Symbol |
|---|---|---|
| Pointer | An address in memory | *int |
| Get address | Find where something lives | & |
| Dereference | Look at what’s at an address | * |
| nil | Empty/no address | nil |
| new() | Create memory, get address | new(type) |
| Value semantics | Work with copies | Normal params |
| Reference semantics | Share the original | Pointer params |
🌟 Remember This!
&= “What’s your address?”*= “Let me visit that address”nil= “No address written yet”new()= “Build me a house and give me the address”- Value = Copy the whole thing
- Reference = Share the location
You’ve now mastered the art of pointers in Go! They’re just addresses — nothing scary about knowing where things live! 🏠✨
