C Cheat Sheet
Cheat Sheet
Off By One Rules
Off By One problems are annoying.
I try to stick to these rules for consistency.
Half Open Ranges
The start index is included and the end index is NOT included
The example below, an array has a length of 5 items.
Iterating starting at the 0 index, the loop MUST terminate at n-1, otherwise there will be an out of bounds error.
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]); // n = 5
for (int i = 0; i < n; i++) {
printf("%x/n", arr[i])
}
Rules
- array sizes MUST be the length of the array (not the 0th indexed length)
int n = sizeof(arr) / sizeof(arr[0]); // n = 5
- loops must always be
i < n
NOTi <= n
since this is EXCLUSIVE of the end
for (int i = 0; i < n; i++) {
printf("%x/n", arr[i])
}
Array slices should be half-open
[start, end)
, end is not included. It’s everything UP TO END BUT NOT INCLUDING.Computing the length given start and end is always:
// Given indexes
int len = end - start;
or
int len = sizeof(arr) / sizeof(arr[0]);
Empty ranges are expressed as:
[start, start)
A single element range is:
[index, index + 1)
, because its not inclusive.Function parameters should also be Half Open in range:
void printRange(int arr[], int start, int end)
Splitting sub-arrays, now can just use the Half open range without +1/-1 to avoid overlap.
[start, mid)
[mid, end)
- Recursive base cases with indexes, this is because recursive functions usually bottom out when there is only 1 or 0 items left
if (end - start <= 1) return;
- Iterating and comparing items in an array:
I think this is safer because, using arr[i + 1]
would end in it out bounds.
Starting at 1 allows the comparison with -1
and will terminate using the half open rule.
Drawback - arr_size must be at least 1 , if its 0 then there be undefined behaviour.
for (int i = 1; i < arr_size; i++) {
if (arr[i] < arr[i - 1]) {
...
...
- Finding the mid point given indexes into an array:
It allows computing the mid using a non-zero start
int mid = start + (end - start) / 2
Pointers
const variable
- Variable cannot be mutated but the pointer can be mutated
const int *arr = {1, 2, 3, 4};
arr[0] = 5; // ERROR
arr = NULL; // OK
const pointer
- Pointer cannot be mutated but the variable can be mutated
const int *arr = {1, 2, 3, 4};
arr = NULL; // ERROR
arr[0] = 5; // OK
const variable const pointer
- Pointer cannot be mutated and the variable cannot be mutated
const int *const arr = {1, 2, 3, 4};
arr[0] = 5; // ERROR
arr = NULL; // ERROR
Macros
- Macros don’t specify a return type in their definition, since they are preproccessed and expanded using the operands type
#pragma once
#define ARR_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#define ARR_SIZE_PTR(ptr, size) (size / sizeof((ptr)[0]))
Makefiles and Compilation
Creating Static Libraries
A static library is reusable code that can be imported and linked at compile time.
CC = gcc
CFLAGS = -Wall -std=c99 -g -O2
# Targets
SRC = $(wildcard src/*.c)
TEST_SRC = $(wildcard tests/*.c)
OBJS = $(SRC:.c=.o)
LIB = libcommon.a
all: $(LIB)
$(LIB): $(OBJS)
ar rcs $(LIB) $(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
test: $(SRC)
$(CC) $(CFLAGS) $(TEST_SRC) $(SRC) -o test_runner
run_test: test
./test_runner
clean:
rm -f $(OBJS) $(LIB) test_runner
CFLAGS
:-Wall
: enables warnings on compilation-std=c99
: compiled with c99 standard-g
: enables debug information for tools like gdbO2
: enables optimization
SRC
: using a wildcard, gets all c files in srcTEST_SRC
: using a wildcard, gets all c files in testsOBJS
: used to convert all c files in src to object filesLIB
: the name of the static libraryall: $(LIB)
: the default command for the makefile, it will build the static library$(LIB): $(OBJS)
: declares that the library depends on the object files in srcar
: the archive command for creating static libraries in Unixrcs
:r
: adds the object files into the library archivec
: creates the archive if it doesn’t exists
: adds an index to the archive to speed up linking
$(LIB) $(OBJ)
: the target and inputs for archiving
%.o: %.c
: wildcare for any object file depends on c files$(CC) $(CFLAGS) -c $< -o $@
:$<
: declares a prerequisite that the c files must be compiled-o $@
: the target output rule
test: $(SRC)
: compiles the test and relies on the srcrun_test: test
: run the test binary but relies and runs test beforeclean
: remove all generated artifacts
GDB
A useful debugger for C.
- If you are debugging a test binary and you would like to set breakpoints in the testing code:
set environment CK_FORK=no
- Starting the debugger in a terminal user interface
gdb -tui ./binary
Commands
start
- starts the debugger to enable move line by linestep
- moves to the next commandstep <N>
- steo through the program over the nextN
commandsprint <variable>
- prints the value of a variable in the program