C Caveats
I needed to dabble in C again, and of course I had forgotten almost everything about it...
Pointers
int *np; // np is a pointer to an int. Read: "*np is of type int".
*np = 3; // Errror! You are dereferencing an unitialized pointer.
// The address stored in np is most likely garbage.
int num = 3; // Now there is actually something we can point to.
np = &num // Makes np point to num.
*np = 4 // * dereferences the pointer, so that you can write/read what
// it is pointing to. Both num and *np now "are" 4.
np // this is just the value of the pointer, i.e. an adress
np+1 // Points to the next element. Depending on architecture and
// typeof(*np), the actual address may be bigger by 1,2,4,...
*np++ // Note the precedence: it is *(np++), meaning: give me the
// value stored at np, and incr. the pointer.
Null vs. Void
int *np = NULL; // NULL is a preprocessor macro that makes the
// pointer point to "nothing interesting", "something safe."
void *np2; // Declares a generic pointer. Points to "void", which is
// a type, just like int and float, only it's always empty.
// A void pointer is a "promiscuous" pointer. Use it if you
// can't say what it will end up pointing to. This, on purpose,
// circumvents the strict static typing of C.
Static vs. Const
const int a = 3; // a is a variable (with allocated memory!) that is not allowed
// to change. You can still change it via pointers. Don't.
# define a 3 // The symbol "a" is replaced by the symbol "3" by the
// preprocessor. It (probably) won't take up memory.
const int *ap; // ap is a pointer to a const int. Often used when pointers are
// passed to functions, and the functions are not allowed to
// change the content that the pointers point to.
int * const ap; // ap is a "constant pointer", meaning the pointer must not
// change. You can change what it points to, though. Array
// names are like this. (?)
int arr[10]; // somewhat comparable to int * const arr. (?)
static int a = 3 // If in a function: Compiler "initializes" it and let's the
// function have access to it. Value is "remembered" through
// multiple function calls.
static void fun(void) {..}
// Caution: Meaning is different now, outside function: fun
// is only "visible" from the same (object) file.
Declare vs. Define vs. Initialize
extern int a; // Declaration: Tell compiler about a thing "int a". This thing
// is defined somewhere else, though, so don't reserve memory.
int b; // Declaration + (tentative) definition: Compiler reserves
// memory. Tentative: If there is another, agreeing one, it's ok.
int b; // Legal because "tentative definition".
float b; // error
int b = 3; // Declaration, definition and initialization in one statement.
// Memory is reserved and filled with meaningful stuff.