What is a Pointer?
In Go, a pointer is a variable that** stores the memory address** of another variable. Instead of holding a value directly, it points to the location where the value is stored.
Syntax
var x int = 10
var p *int = &x // p is a pointer to x
- &x: address-of operator — gets the memory address of variable x.
- *p: dereference operator — gets the value from the address p is pointing to.
Why Use Pointers?
- To share data across function calls without copying.
- To modify variables inside functions.
- To build data structures like linked lists, trees, etc.
- To optimize memory usage and performance by avoiding unnecessary copies.
Declaring and Using Pointers
var a int = 42
var p *int = &a
fmt.Println("Value of a:", a) // 42
fmt.Println("Address of a:", &a)
fmt.Println("Value of p:", p) // address of a
fmt.Println("Value at p:", *p) // 42
Pointer Zero Value
The zero value of a pointer is nil.
var p *int
fmt.Println(p) // <nil>
Always check for nil before dereferencing a pointer:
if p != nil {
fmt.Println(*p)
}
Passing Pointers to Functions
By Value (copy)
func increment(n int) {
n++
}
This won't affect the original value.
By Pointer (reference)
func incrementPtr(n *int) {
*n++
}
x := 5
incrementPtr(&x)
fmt.Println(x) // 6
Returning Pointers from Functions
It's safe to return pointers to local variables in Go — the compiler allocates them on the heap if necessary.
func createPointer() *int {
x := 100
return &x
}
Structs and Pointers
Value Receiver
type User struct {
Name string
}
func (u User) Update(name string) {
u.Name = name // Doesn't affect the original
}
Pointer Receiver
func (u *User) Update(name string) {
u.Name = name // Modifies the original
}
Calling pointer receivers on values (and vice versa)
Go automatically converts between values and pointers when calling methods:
u := User{}
u.Update("Alice") // works even if Update expects *User
Pointers and Arrays/Slices
Arrays are value types
func modifyArray(arr [3]int) {
arr[0] = 100
}
Won't affect original array.
Use a pointer to modify array
func modifyArrayPtr(arr *[3]int) {
arr[0] = 100
}
Slices behave like pointers internally
You can modify slice contents without using explicit pointers:
func modifySlice(s []int) {
s[0] = 100 // modifies original slice
}
Pointers to Pointers
Go supports pointers to pointers, but they’re rarely needed in idiomatic Go.
var x int = 10
var p *int = &x
var pp **int = &p
fmt.Println(**pp) // 10
Interface and Pointer Subtleties
Value vs Pointer receivers in interfaces
type Printer interface {
Print()
}
type Data struct{}
func (d Data) Print() { fmt.Println("Value") }
func (d *Data) Print() { fmt.Println("Pointer") }
func main() {
var d Data
var p Printer = &d // works
// var q Printer = d // doesn't work if only pointer receiver is defined
}
Always ensure your receiver type matches your intended interface use.
Pointers and new Keyword
new(Type) allocates zeroed storage and returns a pointer.
p := new(int) // *int, initialized to 0
*p = 10
Equivalent to:
var x int
p := &x
Pointers and Garbage Collection
Go has garbage collection. You don’t need to free memory manually. Once a pointer is no longer referenced, Go will reclaim the memory.
Best Practices
- Use pointers to avoid copying large structs.
- Use pointer receivers if your method modifies the receiver or avoids copying.
- Avoid pointer-to-interface — use interfaces directly.
- Be careful with nil — always check before dereferencing.
- Prefer slices, maps, and channels over manual pointer-heavy code when possible.
- Avoid using pointers with basic types (like int, bool) unless necessary.
Common Mistakes
Mistake | Explanation |
---|---|
Dereferencing a nil pointer |
Causes runtime panic. Always check for nil . |
Using a pointer to a value that goes out of scope in a goroutine | Safe in Go, but understand escape analysis. |
Modifying value instead of pointer in struct method | Use pointer receiver if modification is needed. |
Pointer to interface | Avoid — interface already holds type and value. |
Pointer Comparison
a := 100
b := 100
p1 := &a
p2 := &a
p3 := &b
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
Pointers are equal if they point to the same memory address.
Example: Swap Function
func swap(a, b *int) {
*a, *b = *b, *a
}
x, y := 1, 2
swap(&x, &y)
fmt.Println(x, y) // 2, 1
Top comments (0)