Pointers in C

Preface

Pointers were one of the most confusing for me while learning C and C++, so here's a little reminder for myself on how they work. Some of the syntax in this post may not compile under a C++ compiler, as C++ isn't a strict superset of C, but the general idea should still apply.

What is a pointer?

A pointer is a number that represents an address in memory where some sort of object is stored. A pointer can also have a value of zero, sometimes called a null pointer, which indicates the pointer points to nothing.

Where does the asterisk go?

// Neat trick to avoid refactoring in the future,
// when calculating the size of the type in malloc, use
// the dereferenced variable name. If the type is
// changed in the future everything will still compile as intended.
int* option1 = malloc(sizeof(*option1));

int * option2 = malloc(sizeof(*option2));

int *option3  = malloc(sizeof(*option3));

All of these are legal syntax. I've seen the first and last syntax before, but I don't know anybody who puts the "*" as it's shown in option two (you're kind of a monster if you do). I believe option 3 is what is suggested by K&R, with the logic being that it reflects how you would use the dereference operator to get what's pointed to. While I understand this idea, I still prefer to use option one, as it makes it much more clear that the variable type is a pointer.

Using const with pointers

The const modifier is "left associative", which means that it binds to whatever is to its left. The exception to this is when there's nothing to its left, where instead it will bind to the right. I choose to always bind to the left, as it makes reading const pointers to const objects easier (pointer three in the following code). In general, you can read the type of the variable from right to left to understand what it is.

// the pointer can point anywhere in memory,
// but you can't modify the data at the address
// "pointer to constant object"
int const* one = malloc(sizeof(*one));

// the pointer can only ever point to this one memory address,
// but I can change the data there
// "constant pointer to object"
int* const two = malloc(sizeof(*two));

// the pointer can only point at this one memory address,
// and I can't modify the data there
// "constant pointer to constant object"
int const* const three = malloc(sizeof(*three));

Generating compile_commands.json

What the heck is this?

When I first started doing C++ programming this Summer with Grail, I wanted to use Emacs as my primary editor. I quickly found out that ccls exists, and was well integrated into Doom Emacs. The primary issue with this setup was that ccls couldn't tell where different imports were, and kept giving an error. The way that Clang based language servers (like clangd) work is they require a compile_commands.json file which contains the commands that run on each file in the project when compiled. Without one of these, the language server doesn't know how to index the project, and starts throwing out false errors.

How do I get one?

The easy way

If your project uses CMake, set the variable CMAKE_EXPORT_COMPILE_COMMANDS to ON and a compile_commands.json will generate in the build folder. Symlink that thing to the root directory of the project and you're good to go.

If you like to have your sanity while using a build system and use Meson, the JSON file should be automatically generated for you and placed in your build files folder.

The slightly more painful way

If your project doesn't use CMake (Grail used a bizarre and confusing system using make before this Summer), the best way to generate one of these files is going to be with bear. As per the README, generating the file is as easy as:

bear -- <your-build-command>