Go Essentials

Go Essentials

Go Essentials

Stacks and Pointers in Go

Stacks and Pointers in Go

Understanding the Go language's memory management and pointer behavior is crucial for writing efficient and performant code. Let's explore the Go language mechanics related to stacks and pointers.

Stack vs. Heap

Go uses a combination of stack and heap for memory management. The stack is used for storing local variables and function call frames. It has a fixed size and is managed automatically by the Go runtime. When a function is called, its local variables are allocated on the stack, and when the function returns, the stack space is freed.

On the other hand, the heap is used for dynamically allocated memory. Variables created using new() or make() functions are allocated on the heap. The heap provides more flexibility for managing memory but requires explicit garbage collection to free memory that is no longer in use.

Pointers in Go

Pointers are variables that store the memory address of another variable. They indicate mutable parameters. They allow you to directly access and modify the value of the variable they point to. Pointers are essential for working with large data structures, avoiding unnecessary memory copies, and passing values by reference.

In Go, you can declare a pointer using the symbol followed by the variable type it points to. To access the value stored at the memory address pointed by a pointer, use the symbol again.

package main

import "fmt"

func main() {
    x := 10
    ptr := &x // ptr is a pointer to the memory address of x

    fmt.Println("Value of x:", x)    // Output: Value of x: 10
    fmt.Println("Value at ptr:", *ptr) // Output: Value at ptr: 10

    *ptr = 20 // Change the value at the memory address
    fmt.Println("Updated x:", x) // Output: Updated x: 20
}

Pointers in Function Arguments

Passing pointers as function arguments allows you to modify the original values directly rather than working with a copy of the data.

package main

import "fmt"

func double(number *int) {
    *number *= 2
}

func main() {
    x := 10
    fmt.Println("Original value of x:", x) // Output: Original value of x: 10

    double(&x)
    fmt.Println("Doubled value of x:", x) // Output: Doubled value of x: 20
}

Pointers and Slices

Slices in Go are references to an underlying array. When you pass a slice to a function, you're passing a reference to the same underlying array, not a copy of the data.

package main

import "fmt"

func modifySlice(slice []int) {
    slice[0] = 100
}

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    fmt.Println("Original Slice:", numbers) // Output: Original Slice: [1 2 3 4 5]

    modifySlice(numbers)
    fmt.Println("Modified Slice:", numbers) // Output: Modified Slice: [100 2 3 4 5]
}

You should learn deeply about memory management in Go as it is crucial in real-world systems. This is because if pointers are not used carefully, they can hinder the application's performance and overload the Go garbage collector.

Whenever you're ready

There are 4 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Get Backend Jobs

Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board