C Preprocessor

C preprocessor code will be executed before compiling the actual c code.
Preprocessor lines start with # and do not end with a semicolon (in contrast to usual code instructions).

#define MAX_SIZE = 1
#undef MAX_SIZE

The first instruction replaces instances of MAX_SIZE with 1. The second instruction undefines the previous made call.


#include <stdio.h>
#include "myheader.h"

Tells the cpp to include stdio.h from the system libraries, where else the next line includes the header file myheader.h from the local directory.

#ifndef MAX_SIZE 

#ifdef DEBUG


A pointer points to a variable address/stores a variable address.

char val = 'c';
char val2;
char *pointer = &val;
val2 = *pointer;

& is used to get the address of a variable, * to an already declared pointer gives us the actual value again.
We initialize the pointer in line 3 and set val2 to the actual value of the pointer (c in this case).


A string is basically an array of characters, which by default also ends with a null character (\0) indicating the end of the string. If a pointer points to the string, then it will hold the starting address of the string (the first character).

char *pointer = "Some string";
printf("%c, %s", *pointer, pointer);

Above code outputs S, Some string. We get the value of the first character followed by the full string, as the format specifier %s lets us print out all characters of the array until it reaches a null character.

Pointers and Structs

struct student {
    int a;
    int b;
} obj;

struct *s = &obj;
s->a = 5;
s->b = 1;

Accessing pointer objects is done with -> instead of ..

Data Structures


Grouping of a list of variables.

struct student {
    int student_id;
    float balance; 

struct student s1;
s1.student_id = 1;


struct student {
    int student_id;
    float balance;
} s1, s2;


Gives a type a new name.

typedef unsigned long long ull;
ull a, b;

Also useful in regard to structs:

typedef struct student {
    int student_id;
    float balance;
} Student;

Student s1;
s1.student_id = 1;

Error Handling

Taken from the errno(3) linux man page:

The <errno.h> header file defines the integer variable errno, which
is set by system calls and some library functions in the event of an
error to indicate what went wrong.

The function void perror(const char *str) lets you pass a custom C string, which will be displayed before the actual error message.

fp = fopen("file.txt", "r");
if (fp == NULL) {
    perror("file.txt: ");

The above code could output something like this: file.txt: No such file or directory.

Another useful function would be char *strerror(int errnum), which acts similar to perror, except it returns a pointer to the error message string. Following code should print out the same as the above one.

fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("file.txt: %s", strerror(errno));

Program Structure

Top-Down/Procedural programming

Mix everything in one pot and hope that your pot is still edible after mixing it for years. Therefore, it would be more clever to split your growing pot into so called modules: split code into several c files, combine declarations into header files.

Object Oriented Programming

The new deal within the programming industry.

Visibility of Variables/Functions

Folder with examples to this sub section can be found here.

  1. global visibility (over modules and functions)
  2. global visibility in a module (over functions within the module)
  3. local visibility within a function
  4. local visibility within a block

Overriding happens as we go from bottom to top.

To use variables, which are already defined in another source file: extern int x;.
Limiting the visiblity to a module happens with the keyword static.

Lifespan of Variables

Space of global variables are reserved during the total runtime of our program.

  1. static variables (static)
    • space reserved as in the default behaviour for global variables
    • static variables have the value 0 when not initialized
  2. dynamic variables (auto)
    • local variables
    • auto variables have undefined values when not initialized
    • space reserved during runtime of a block, freed when leaving the block