Go Pointers
Memory addresses and references in Go programming
👉 What are Go Pointers?
Pointers store memory addresses of variables instead of values. They allow you to directly access and modify data in memory, enabling efficient data sharing and manipulation.
// Create a pointer
x := 42
ptr := &x // ptr holds address of x
fmt.Println(*ptr) // Output: 42 (value at address)
Output:
42
Key Pointer Concepts
Memory Address
Pointers store memory locations
x := 10
ptr := &x // ptr = address of x
Dereferencing
Access values through pointers
value := *ptr // Get value at address
Direct Modification
Change original values via pointers
*ptr = 20 // Changes original variable
Efficiency
Pass large data without copying
func modify(ptr *BigStruct) {
// No copying needed
}
🔹 Basic Pointer Operations
Understanding address-of (&) and dereference (*) operators:
package main
import "fmt"
func main() {
// Regular variable
number := 42
fmt.Println("Value of number:", number)
fmt.Println("Address of number:", &number)
// Create a pointer
ptr := &number
fmt.Println("Pointer ptr holds address:", ptr)
fmt.Println("Value at address (dereference):", *ptr)
// Modify through pointer
*ptr = 100
fmt.Println("After modifying through pointer:")
fmt.Println("number is now:", number)
fmt.Println("*ptr is now:", *ptr)
// Pointer to pointer
ptrToPtr := &ptr
fmt.Println("Address of ptr:", ptrToPtr)
fmt.Println("Value through double dereference:", **ptrToPtr)
}
Output:
Value of number: 42
Address of number: 0xc0000140b8
Pointer ptr holds address: 0xc0000140b8
Value at address (dereference): 42
After modifying through pointer:
number is now: 100
*ptr is now: 100
Address of ptr: 0xc000006028
Value through double dereference: 100
🔹 Pointers with Functions
Use pointers to modify variables inside functions:
package main
import "fmt"
// Function with value parameter (creates copy)
func doubleValue(x int) {
x = x * 2
fmt.Println("Inside doubleValue:", x)
}
// Function with pointer parameter (modifies original)
func doublePointer(x *int) {
*x = *x * 2
fmt.Println("Inside doublePointer:", *x)
}
// Function that returns a pointer
func createPointer(value int) *int {
return &value
}
func main() {
number := 10
fmt.Println("Original number:", number)
// Pass by value - original unchanged
doubleValue(number)
fmt.Println("After doubleValue:", number)
// Pass by pointer - original modified
doublePointer(&number)
fmt.Println("After doublePointer:", number)
// Get pointer from function
ptr := createPointer(50)
fmt.Println("Pointer from function:", *ptr)
}
Output:
Original number: 10
Inside doubleValue: 20
After doubleValue: 10
Inside doublePointer: 20
After doublePointer: 20
Pointer from function: 50
🔹 Pointers with Structs
Pointers are commonly used with structs for efficiency:
package main
import "fmt"
type Person struct {
Name string
Age int
}
// Method with pointer receiver
func (p *Person) Birthday() {
p.Age++
fmt.Printf("%s is now %d years old\n", p.Name, p.Age)
}
// Function that takes pointer to struct
func updateName(p *Person, newName string) {
p.Name = newName
}
func main() {
// Create struct
person := Person{Name: "Alice", Age: 25}
fmt.Println("Original:", person)
// Get pointer to struct
personPtr := &person
// Access fields through pointer (automatic dereferencing)
fmt.Println("Name through pointer:", personPtr.Name)
fmt.Println("Age through pointer:", personPtr.Age)
// Modify through pointer
personPtr.Name = "Alice Smith"
personPtr.Age = 26
fmt.Println("After modification:", person)
// Call method (automatically takes address)
person.Birthday()
// Pass pointer to function
updateName(&person, "Alice Johnson")
fmt.Println("After name update:", person)
// Create pointer directly
anotherPerson := &Person{Name: "Bob", Age: 30}
fmt.Println("Direct pointer creation:", *anotherPerson)
}
Output:
Original: {Alice 25}
Name through pointer: Alice
Age through pointer: 25
After modification: {Alice Smith 26}
Alice Smith is now 27 years old
After name update: {Alice Johnson 27}
Direct pointer creation: {Bob 30}
🔹 Nil Pointers and Safety
Understanding nil pointers and safe pointer usage:
package main
import "fmt"
func main() {
// Nil pointer
var ptr *int
fmt.Println("Nil pointer:", ptr)
fmt.Println("Is nil?", ptr == nil)
// Safe pointer check before dereferencing
if ptr != nil {
fmt.Println("Value:", *ptr)
} else {
fmt.Println("Cannot dereference nil pointer")
}
// Create valid pointer
number := 42
ptr = &number
fmt.Println("Valid pointer:", ptr)
fmt.Println("Is nil?", ptr == nil)
if ptr != nil {
fmt.Println("Safe to dereference:", *ptr)
}
// Using new() function
newPtr := new(int) // Creates pointer to zero value
fmt.Println("New pointer:", newPtr)
fmt.Println("Value at new pointer:", *newPtr)
*newPtr = 100
fmt.Println("After assignment:", *newPtr)
}
Output:
Nil pointer: <nil>
Is nil? true
Cannot dereference nil pointer
Valid pointer: 0xc0000140b8
Is nil? false
Safe to dereference: 42
New pointer: 0xc0000140c0
Value at new pointer: 0
After assignment: 100