Mastering Memory: A Beginner's Guide to Comparing Pointers in Go

Shivam DubeyShivam Dubey
6 min read

In Go, pointers are a powerful tool for working with memory. While understanding how to use pointers is essential, knowing how to compare pointers is equally important for managing memory effectively. In this article, we will explain how to compare pointers step by step with examples and their outputs, making it beginner-friendly.


Recap: What Are Pointers?

A pointer is a variable that stores the memory address of another variable. Instead of storing a value directly, a pointer "points" to the memory location where the value is stored.

Quick Overview of Pointer Concepts

  • Declaration: Use * to declare a pointer.

  • Address-of Operator (&): Retrieves the memory address of a variable.

  • Dereferencing (*): Accesses or modifies the value stored at the memory location a pointer refers to.

Here’s a simple example to refresh your understanding:

package main

import "fmt"

func main() {
    num := 42
    ptr := &num // Pointer to num

    fmt.Println("Address of num:", ptr)    // Prints the memory address of num
    fmt.Println("Value via pointer:", *ptr) // Dereferences pointer to print 42
}

Output

Address of num: 0xc000014098
Value via pointer: 42

Can Pointers Be Compared in Go?

Yes! Go allows you to compare pointers using comparison operators:

  1. Equality (==): Checks if two pointers refer to the same memory location.

  2. Inequality (!=): Checks if two pointers refer to different memory locations.


Example: Comparing Pointers

Here’s an example demonstrating how to compare pointers using == and !=:

package main

import "fmt"

func main() {
    a := 10
    b := 10

    ptr1 := &a // Pointer to a
    ptr2 := &b // Pointer to b
    ptr3 := &a // Another pointer to a

    // Compare pointers
    fmt.Println("ptr1 == ptr2:", ptr1 == ptr2) // False: Different memory locations
    fmt.Println("ptr1 == ptr3:", ptr1 == ptr3) // True: Same memory location
    fmt.Println("ptr1 != ptr2:", ptr1 != ptr2) // True: Different memory locations
}

Output

ptr1 == ptr2: false
ptr1 == ptr3: true
ptr1 != ptr2: true

Explanation

  1. ptr1 == ptr2: a and b are separate variables, so their memory addresses differ.

  2. ptr1 == ptr3: Both ptr1 and ptr3 point to the same variable a.

  3. ptr1 != ptr2: Since ptr1 and ptr2 point to different locations, the result is true.


Comparing Nil Pointers

A nil pointer is a pointer that does not refer to any memory location. Comparing pointers to nil is common in Go to check if they are uninitialized or valid.

Example: Checking for Nil Pointers

package main

import "fmt"

func main() {
    var ptr *int // Declares a nil pointer

    if ptr == nil {
        fmt.Println("Pointer is nil") // Prints this
    } else {
        fmt.Println("Pointer is not nil")
    }

    num := 42
    ptr = &num // Now ptr points to num

    if ptr != nil {
        fmt.Println("Pointer is not nil") // Prints this
    }
}

Output

Pointer is nil
Pointer is not nil

Explanation

  1. ptr == nil: Initially, ptr is a nil pointer since it is not initialized.

  2. ptr != nil: After assigning the address of num to ptr, it now points to valid memory.


Practical Use Case: Checking Shared Memory

Pointers are often used to determine if two variables share the same memory location.

Example: Are Two Variables the Same?

package main

import "fmt"

func isSameMemory(ptr1, ptr2 *int) bool {
    return ptr1 == ptr2 // Compare pointers
}

func main() {
    a := 10
    b := 10
    c := a // Copy of a

    ptr1 := &a
    ptr2 := &b
    ptr3 := &c

    fmt.Println("ptr1 and ptr2:", isSameMemory(ptr1, ptr2)) // False
    fmt.Println("ptr1 and ptr3:", isSameMemory(ptr1, ptr3)) // False
}

Output

ptr1 and ptr2: false
ptr1 and ptr3: false

Explanation

  1. ptr1 and ptr2: Although a and b have the same value (10), they are stored in different memory locations.

  2. ptr1 and ptr3: Even though c is a copy of a, it is stored in a different memory location.


Summary of Pointer Comparison Rules

  1. Valid Comparisons:

    • You can use == and != to compare pointers.

    • You can check if a pointer is nil.

  2. What Is Compared:

    • The memory addresses stored in the pointers are compared, not the values at those addresses.
  3. Go-Specific Features:

    • Go does not allow pointer arithmetic (e.g., ptr+1).

    • Go’s garbage collector ensures safe memory management, reducing the risk of dangling pointers.


Passing by Value vs. Passing by Reference

In Go, when you pass a variable to a function, it is passed by value by default. This means a copy of the value is passed, and the original value remains unchanged.

Passing by Value

package main

import "fmt"

func incrementByValue(num int) {
    num++
    fmt.Println("Inside function (by value):", num)
}

func main() {
    value := 10
    incrementByValue(value)
    fmt.Println("Outside function (by value):", value)
}

Output

Inside function (by value): 11  
Outside function (by value): 10

Explanation

  • The value variable remains unchanged because the function works with a copy.

Passing by Reference

To modify the original value, pass a pointer to the function.

goCopy codepackage main

import "fmt"

func incrementByReference(num *int) {
    *num++ // Dereference pointer to increment value
    fmt.Println("Inside function (by reference):", *num)
}

func main() {
    value := 10
    incrementByReference(&value) // Pass the address of value
    fmt.Println("Outside function (by reference):", value)
}

Output

Inside function (by reference): 11  
Outside function (by reference): 11

Explanation

  1. &value: Passes the memory address of value to the function.

  2. *num++: Dereferences the pointer to modify the original value.


Key Differences Between Passing by Value and Passing by Reference

FeaturePassing by ValuePassing by Reference
What is passedA copy of the value.The memory address of the value.
Original valueRemains unchanged.Can be modified.
UsageSafe for read-only operations.Useful for modifying values.

Summary

Here’s what we covered:

  1. Pointers and References: Pointers store memory addresses, allowing you to work with data indirectly.

  2. Dereferencing: Access or modify the value stored at a memory address using *.

  3. new Function: Allocates memory and returns a pointer to the zero value of the type.

  4. Passing by Value vs. Reference: Use pointers when you need to modify the original value inside a function.


Conclusion

Comparing pointers is an essential part of understanding Go’s memory management. By checking whether two pointers refer to the same or different memory locations, you can control how data is shared and manipulated.

Practice these examples to solidify your understanding of pointers in Go, and stay tuned for more tutorials exploring advanced memory and pointer concepts. Keep coding, and happy learning! 🚀

0
Subscribe to my newsletter

Read articles from Shivam Dubey directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shivam Dubey
Shivam Dubey