By day, I am a Software Engineer. I build scalable systems using TypeScript and NestJS. I am used to Garbage Collectors and strict typing that only exists before compilation.
By night, I leave that comfort zone. I am on a mission to understand First Principles. I want to stop being just a coder and become a Systems Engineer.
I used to be ignorant about memory. I thought, "Who cares? Hardware is cheap.". I was wrong. Here is what I learned when I stopped relying on abstractions and started looking at the raw bytes.
1. Memory Padding: Your Data is Wasting Space
In TypeScript, we don't care how an object is stored. In C, if you don't care, you pay the price.
Look at this struct:
typedef struct {
char a; // 1 byte
double b; // 8 bytes
int c; // 4 bytes
} Point;
How big is this? Math says 1 + 8 + 4 = 13 bytes. If you say 13, you are wrong. The answer is 24 bytes.
Why? Because the CPU is picky, it fetches data in aligned chunks (usually 8 bytes), it cannot grab that double easily if it is stuck between two chunks. So, the compiler adds an invisible padding, empty bytes to align it.
In this simple struct, we wasted 11 bytes just for padding. I learned that just by reordering the struct (putting int before double), I could reduce the padding to only 3 bytes. High-level languages hide this from you. C forces you to see it.
2. "Don't Reinvent the Wheel" is Bad Advice
People say: Never rewrite the standard library. I say: Rewrite it, or you will never understand how it works.
I spent days rebuilding realloc and memcpy from scratch. You think you understand Dynamic Memory Allocation? You don't. Not until you manually calculate byte size, malloc a new block, loop through the old block to copy bytes one by one, and then free the old pointer.
If you only use the built-in functions, you are just a consumer, not an engineer.
3. The Paradox: Why "One Loop" is Slower than "Two Loops"
This was a hard lesson for me. I had a challenge: remove duplicates from an array. My first attempt was simple: "I want to be efficient. I will do it in one pass."
- Loop through the array.
- If I find a unique item, use realloc to grow the array and add it.
It sounded smart. But actually, it was garbage.
The Problem: realloc is expensive. Very expensive. It often has to find a new memory block, copy everything to the new place, and delete the old one. My "efficient" loop was triggering heavy memory operations constantly.
The Better Way (Instructor's Method):
- Loop once just to count the unique items.
- malloc once with the exact size.
- Loop again to fill it.
Iterating twice is actually faster here.
Think about packing a suitcase. My way was: put one sock in a small bag. Bag is full? Buy a bigger bag, move the sock, add a shirt. Bag is full? Buy a bigger bag... The better way: Lay everything on the floor. See exactly how big it is. Buy the right suitcase once. Pack it.
4. Pointers to Pointers (The Real Headache)
You think pointers are hard? Try ***ptr (Pointer to Pointer to Pointer).
I struggled with this when trying to allocate 2D arrays by reference. I kept getting "Segmentation Faults" because I was writing *(ref[i]) instead of (*ref)[i]. The brackets matter.
But you need this. It simplifies memory management. If you want to swap rows in a matrix, you don't move the values. You just swap the pointers using an XOR operation. It is cleaner and faster.
5. Discipline Over Syntax
I finished this learning phase by building a School Management System.
The code wasn't complex. The logic was standard. The hard part was the discipline.
- Every malloc needs a free.
- If I remove a Student from a Course, I must update the Average Grade immediately.
- No memory leaks allowed.
In NestJS, I structure my code to be readable. In C, I structure my data to survive.
Conclusion
I am still a "wannabe" Systems Engineer. My code is not perfect. My repo is just a "scratchpad", no documentation, just raw learning.
But at least now, I am not ignorant. I know what happens under the hood.
If you want to check my journey or laugh at my code, here is the repo: github.com/fauzanfebrian/c-memory-playground
Top comments (0)