đź§ What Are Pointers in Go? A Simple Guide for Beginners
Confused about pointers in Go? You're not alone. In this post, we’ll break down what pointers are, why they matter, and how to use them — all with simple analogies and real code examples.
🔤 What Is a Pointer?
At its core, a pointer is just a memory address.
Think of your computer’s memory like a giant apartment building, where each apartment (memory location) has a unique number (address). When you create a variable in Go, it gets stored in one of these "apartments."
A pointer doesn’t store the value itself — it stores which apartment (address) the value lives in.
âś… A pointer is a variable that holds the memory address of another variable.
🏠Real-World Analogy
Imagine you have a friend named Alice who lives at:
123 Memory Lane
You don’t carry her house around with you — you just write down her address.
Now, if someone asks you where Alice is, you can say:
“She lives at 123 Memory Lane.”
In programming:
- The house = a variable (e.g.,
num := 10
) - The address = a pointer (e.g.,
&num
) - Going to the house and changing something inside = dereferencing the pointer
This is exactly how pointers work!
⚙️ The Two Key Symbols: &
and *
There are only two symbols you need to understand:
Symbol | Name | Meaning |
---|---|---|
& |
Ampersand | "Address of" → gives you the memory address |
* |
Asterisk | "Value at" → accesses the data at that address |
Let’s see them in action.
package main
import "fmt"
func main() {
num := 42
fmt.Println("Value:", num) // 42
fmt.Println("Address:", &num) // e.g., 0xc00001a0b8
}
Output:
Value: 42
Address: 0xc00001a0b8
Here, &num
gives us the address where 42
is stored.
Now let’s store that address in a pointer:
var ptr *int = &num
fmt.Println("Pointer:", ptr) // 0xc00001a0b8
fmt.Println("Value at ptr:", *ptr) // 42
-
ptr
holds the address. -
*ptr
means: “go to that address and get the value.”
We call *ptr
dereferencing the pointer.
âť“ Why Do We Need Pointers?
Go passes arguments to functions by value, which means it makes a copy of the data.
This leads to a big problem...
🟡 Problem: Can’t Modify Variables in Functions
func changeValue(x int) {
x = 100
}
func main() {
num := 1
changeValue(num)
fmt.Println(num) // Still prints 1 → Not changed!
}
Why? Because changeValue
only modifies its copy of num
, not the original.
âś… Solution: Use a Pointer
Instead of passing the value, pass the address of the variable.
func changeValueWithPointer(x *int) {
*x = 100 // Modify the original value
}
func main() {
num := 1
changeValueWithPointer(&num) // Pass the address
fmt.Println(num) // Now prints 100 âś…
}
Now it works! The function uses the pointer to modify the original variable.
🛠️ How to Declare and Use Pointers
1. Declare a Pointer
var ptr *int
- This creates a pointer to an integer (but it’s
nil
for now).
2. Assign an Address
num := 25
ptr = &num
3. Dereference to Read or Write
fmt.Println(*ptr) // Read: prints 25
*ptr = 50 // Write: changes num to 50
đź’ˇ When Should You Use Pointers?
Use Case | Why |
---|---|
Modify variables in functions | Pass a pointer to change the original |
Avoid copying large structs | Passing a pointer (8 bytes) is faster than copying KBs of data |
Share data between functions | Multiple parts of your program can access the same data |
Working with slices, maps, channels | These types are reference-like, but understanding pointers helps you debug and design better |
⚠️ Common Pitfall: Nil Pointer Dereference
Never dereference a nil
pointer — it will crash your program!
var p *int
fmt.Println(*p) // đź’Ą PANIC: invalid memory address
Always make sure your pointer points to valid memory before using *p
.
đź§Ş Example: Swapping Two Numbers
Here’s a classic use case: swap two numbers using pointers.
func swap(a, b *int) {
*a, *b = *b, *a // Dereference and swap
}
func main() {
x, y := 5, 10
fmt.Println("Before:", x, y) // 5 10
swap(&x, &y)
fmt.Println("After:", x, y) // 10 5
}
Without pointers, this would be impossible in Go!
đź§ Summary: Key Takeaways
- A pointer holds the memory address of a variable.
- Use
&
to get the address:&num
- Use
*
to access the value:*ptr
- Pointers let functions modify original variables
- They help avoid expensive copies and enable shared state
- Be careful: don’t dereference nil pointers
📚 Final Thought
Pointers may seem scary at first, but once you think of them as addresses to data, they become much simpler.
They are one of Go’s most powerful features — and once you master them, you’ll write more efficient, flexible, and expressive code.
🔗 Remember: A pointer doesn’t hold the treasure. It holds the map to the treasure.
🙋‍♂️ Got Questions?
Leave a comment below!
*Enjoyed this post? Share it to your friends and follower!
Happy coding! đź’»
Top comments (1)
Fantastic guide! You've done an excellent job of demystifying pointers for newcomers. The treasure map analogy is one of the best I've seen.
Building on your excellent point about pass-by-value, here's a more advanced detail on how slices and maps fit into this model.
They are essentially small structs that contain a pointer to the underlying data. This small struct gets passed by value, but the pointer inside it still allows the function to modify the original data.
This explains the common "gotcha" moment for new developers: when a function alters a map or slice's contents, which can be surprising if you expect pass-by-value to prevent any mutation of the original variable.
Awesome work on this valuable resource!