Don't Cry about Pointers anymore - Deep Dive with C, Go and Rust

Why TF does this blog even exist? Let’s be real — most of us treat pointers like radioactive waste. Let's ignore those dreadful stories of childhood when pointers were introduced to you like a BIG demon. But deep down, the truth is: Memory is power. And pointers? Pointers are your keys to the throne. If you’ve ever: Debugged a nasty segfault while chugging a huge load of coffee, Seen your app lag thanks to the garbage collector, Or tried passing huge structs around to make your code modular … Then you’ve already felt the need for pointers. This isn’t just a blog. This is a manifesto. We’re gonna break the myths, smash the fear, and teach you how to own memory like an absolute menace — across C (just for understanding how pointers work), Go, and Rust. By the end of this read, you’ll understand: What pointers really are Why they matter in modern backend systems How Go gives you a chill but powerful pointer experience How Rust forces you into greatness with ownership and borrowing Let’s cut the fluff and jump right in — welcome to the deep dive. Basics: Pointers and How They Work (I'm Hoping Y'all Know C) A pointer just refers to another value. That's it. It is itself a variable that stores the address of another variable(this variable can be a pointer too). Let's see a quick code snippet in C to recap pointer basics. #include int main() { int x = 42; int *p = &x; // p points to the address of x printf("Value of x: %d\n", x); printf("Pointer p: %p\n", p); // prints address of x printf("Value at *p: %d\n", *p); // dereferencing p, gives 42 *p = 99; // update x through the pointer printf("Updated x: %d\n", x); // now x is 99 return 0; } Key Concepts : *p → Dereference the pointer (get the value it points to) &x → Address-of operator (get the memory address of x) int *p → Declare a pointer to an integer This is where C shows you its true colors: dope performance, minimal overhead — but a single wrong move and it’s undefined behavior land. Manual memory management is both a blessing and a curse. Let's quickly take a look over other pointer shenanigans in C : 1. Pointers and Arrays: int arr[3] = {10, 20, 30}; int *ptr = arr; // same as &arr[0] printf("%d\n", *(ptr + 1)); // prints 20 Arrays decay into pointers — the name of an array is basically a pointer to its first element. 2. Pointer to Pointer: int x = 5; int *p = &x; int **pp = &p; printf("%d\n", **pp); // double dereference A pointer to a pointer holds the address of another pointer. Useful in dynamic memory, linked lists, and certain APIs. 3. Function Pointers: void greet() { printf("Hello!\n"); } void (*funcPtr)() = greet; funcPtr(); // calls greet() Functions live in memory too, and you can point to them! That’s how callbacks and plugin systems are built. 4. Void Pointers: void *vp; int a = 7; vp = &a; printf("%d\n", *(int *)vp); Generic pointers that can point to any type. But you need to cast them back before dereferencing. Wait! There is also pointer arithmetic in C. In C, pointers aren’t just addresses — they’re math-capable beasts. You can add or subtract integers to pointers to move across array elements (ptr + 1 points to the next element). But beware: mess up the math, and you're one *(ptr + 9999) away from summoning a segfault demon.(I swear ChatGPT wrote this!) int arr[5] = {1, 2, 3, 4, 5}; int *ptr = arr; printf("%d\n", *(ptr + 2)); // prints 3 I just skimmed through the surface of pointers in C. You definitely need to go into a lot more detail. If you want to work with pointers in C, burn this video into your head. In C, you need to manage memory manually using malloc or calloc and use the pointers very carefully and cautiously. While you have all the control, things can go south easily, even if you miss a little something. Before diving into how we handle pointer in Go or Rust, let us look at some common concepts in pointers. Pointer 101 Pointer Declaration We already saw how to do this in C, and it is pretty easy in Go and Rust too. These code snippets will help you grasp it. func main() { a := 10 var p *int = &a fmt.Println(*p) // dereferencing } fn main() { let a = 10; let p = &a; // immutable reference println!("{}", *p); } Dynamic Memory Allocation Even here, the code snippets will help you. The pointers are allocated memory in heap. int *p = (int*) malloc(sizeof(int)); *p = 42; p := new(int) *p = 42 let b = Box::new(42); // heap allocation Stack vs Heap Allocation in Pointers When working with pointers in low-level languages like C, Go, and Rust, understanding how memory is allocated — either on the stack or the heap — is non-negotiable if you don’t want your programs to randomly explode (aka segfault). Stack Allocation Fa

Apr 16, 2025 - 17:47
 0
Don't Cry about Pointers anymore - Deep Dive with C, Go and Rust

Why TF does this blog even exist?

Let’s be real — most of us treat pointers like radioactive waste. Let's ignore those dreadful stories of childhood when pointers were introduced to you like a BIG demon. But deep down, the truth is:

Memory is power. And pointers? Pointers are your keys to the throne.

If you’ve ever:

  • Debugged a nasty segfault while chugging a huge load of coffee,
  • Seen your app lag thanks to the garbage collector,
  • Or tried passing huge structs around to make your code modular …

Then you’ve already felt the need for pointers.

This isn’t just a blog. This is a manifesto. We’re gonna break the myths, smash the fear, and teach you how to own memory like an absolute menace — across C (just for understanding how pointers work), Go, and Rust.

By the end of this read, you’ll understand:

  • What pointers really are
  • Why they matter in modern backend systems
  • How Go gives you a chill but powerful pointer experience
  • How Rust forces you into greatness with ownership and borrowing

Let’s cut the fluff and jump right in — welcome to the deep dive.

Basics: Pointers and How They Work (I'm Hoping Y'all Know C)

A pointer just refers to another value. That's it. It is itself a variable that stores the address of another variable(this variable can be a pointer too).
Let's see a quick code snippet in C to recap pointer basics.

#include 

int main() {
    int x = 42;
    int *p = &x; // p points to the address of x

    printf("Value of x: %d\n", x);
    printf("Pointer p: %p\n", p);       // prints address of x
    printf("Value at *p: %d\n", *p);     // dereferencing p, gives 42

    *p = 99; // update x through the pointer
    printf("Updated x: %d\n", x);        // now x is 99

    return 0;
}

Key Concepts :

  • *p → Dereference the pointer (get the value it points to)
  • &x → Address-of operator (get the memory address of x)
  • int *p → Declare a pointer to an integer

Diagram explaining how pointer references work in C

This is where C shows you its true colors: dope performance, minimal overhead — but a single wrong move and it’s undefined behavior land. Manual memory management is both a blessing and a curse.

Let's quickly take a look over other pointer shenanigans in C :

1. Pointers and Arrays:

int arr[3] = {10, 20, 30};
int *ptr = arr; // same as &arr[0]
printf("%d\n", *(ptr + 1)); // prints 20

Arrays decay into pointers — the name of an array is basically a pointer to its first element.

2. Pointer to Pointer:

int x = 5;
int *p = &x;
int **pp = &p;
printf("%d\n", **pp); // double dereference

A pointer to a pointer holds the address of another pointer. Useful in dynamic memory, linked lists, and certain APIs.

3. Function Pointers:

void greet() { printf("Hello!\n"); }
void (*funcPtr)() = greet;
funcPtr(); // calls greet()

Functions live in memory too, and you can point to them! That’s how callbacks and plugin systems are built.

4. Void Pointers:

void *vp;
int a = 7;
vp = &a;
printf("%d\n", *(int *)vp);

Generic pointers that can point to any type. But you need to cast them back before dereferencing.

Wait! There is also pointer arithmetic in C.

In C, pointers aren’t just addresses — they’re math-capable beasts. You can add or subtract integers to pointers to move across array elements (ptr + 1 points to the next element).
But beware: mess up the math, and you're one *(ptr + 9999) away from summoning a segfault demon.(I swear ChatGPT wrote this!)

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;

printf("%d\n", *(ptr + 2)); // prints 3

I just skimmed through the surface of pointers in C. You definitely need to go into a lot more detail. If you want to work with pointers in C, burn this video into your head.

In C, you need to manage memory manually using malloc or calloc and use the pointers very carefully and cautiously. While you have all the control, things can go south easily, even if you miss a little something.

Before diving into how we handle pointer in Go or Rust, let us look at some common concepts in pointers.

Pointer 101

Pointer Declaration

We already saw how to do this in C, and it is pretty easy in Go and Rust too. These code snippets will help you grasp it.

func main() {
    a := 10
    var p *int = &a
    fmt.Println(*p) // dereferencing
}
fn main() {
    let a = 10;
    let p = &a; // immutable reference
    println!("{}", *p);
}

Dynamic Memory Allocation

Even here, the code snippets will help you. The pointers are allocated memory in heap.

int *p = (int*) malloc(sizeof(int));
*p = 42;

p := new(int)
*p = 42

let b = Box::new(42); // heap allocation

Stack vs Heap Allocation in Pointers

When working with pointers in low-level languages like C, Go, and Rust, understanding how memory is allocated — either on the stack or the heap — is non-negotiable if you don’t want your programs to randomly explode (aka segfault).

Stack Allocation

  • Fast and automatically managed.
  • Memory is allocated when a function is called and freed when it returns.
  • Ideal for short-lived variables and function-local data.

C Example:

int main() {
    int x = 42;        // x is on the stack
    int *p = &x;       // p points to stack memory
}

Warning:

Returning a pointer to a stack variable is dangerous. Once the function exits, that memory is gone.

int* bad() {
    int local = 10;
    return &local; //