Low-Level Revelations

I’m learning C for work. I’ve always wanted to immerse with C/C++ but never had a reason to… until now.

I’ve previously played with C++. It has a huge amount of features. But I didn’t realize how big of a language it was until I started learning C. Here’s a list of things that C++ has that C doesn’t:

  • bool type (use a decimal value 0 or 1)
  • Classes (use structs)
  • Overloading operators
  • new and delete operators (use malloc and free)
  • Template functions

Yet even though many of those taken-for-granted features were missing, I found that it was easier to solve problems in C because I wasn’t burdened with the question of how to architect a program. There’s no classes or name spacing, so it’s pretty simple: just use functions and structs.

It turns out that you really don’t need those advanced features or higher level datatypes to get stuff done. With some decent intuition about common data structures, you can solve most problems.

Here’s a function from a word-counting program I made:

Each “WordInfo” object contains a word string, count and pointer to the next word. It iterates through each word and if it finds a match, it iterates the counter for the word. Otherwise it creates an entry for the word at the tail of the list.

My key takeaway from this experience is that under the hood, lists of data are either 1.) aligned next to each other in memory  (as an array) so that you can increment the pointer to get the next item or 2.) can be at any location in memory, but “linked” together by references to each other (linked list or tree structure).

I visualize a train with multiple cabins. To get to a particular cabin, you have to know the location of one of the connected cabins. But if you lose the location to all the cabins, you’re screwed. And if somehow the link between the cabins is lost, you cannot access the disconnected cabins. In a garbage-collected language like Java or JavaScript, the cabins would magically disappear once you lost them. But in C, the cabins will remain existing until explicitly “freed from memory”.

Another thing that I dig about C is how it gives you complete ownership over memory. Most of the functions in the standard library like string.h don’t allocate memory for objects, but instead ask you to pass your own object for mutation. I’m learning how to program in such a way that the number of allocations are reduced and memory is reused, and yet the code is still surprisingly compact.

I’m going deeper down the rabbit hole…

Leave a Reply

Be the First to Comment!