C cheat sheet

A scannable C reference: 19 short snippets across 10 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Syntax and the compiled toolchainC is compiled ahead of time. A single gcc hello.c -o hello hides four stages; running them separately is the fastestlesson
Pointers and memoryA pointer holds an address. The two operators are & (address of) and * (dereference, the value at that address)lesson
Structs, files and undefined behaviourThe standard defines some operations as undefined behaviour: the compiler may assume they never occur and optimiselesson
Setting up a C toolchain: compiler, make and gdbC has no package manager of its own. What you install is a toolchain: a compiler driver (gcc or clang), an assembler, alesson
Arrays, strings and the string libraryIn almost every expression an array name decays to a pointer to its first element. That is why sizeof inside a functionlesson
Dynamic memory patterns and allocation bugsC has no destructors, so ownership is a convention you write down. Pick one rule per pointer and stick to it: thelesson
Preprocessor, headers and multi-file projectsA header declares what other files may use; a .c file defines it. Every header needs an include guard, and anything notlesson
Building and linking: static and shared librariesCompiling (-c) and linking are separate steps. A link error means the compiler was satisfied but the linker could notlesson
Debugging with gdb, sanitizers and valgrindA watchpoint is the fastest way to find who corrupts a variable: set it on the field that goes wrong and gdb stops atlesson
Portability, standards and disciplined CThe standard does not fix the size of int or long. It fixes minimum ranges, so int is 16, 32 or 64 bits depending onlesson

Quick snippets

Syntax and the compiled toolchain

From source to executable

gcc -E hello.c -o hello.i     # preprocess: #include and #define are expanded
gcc -S hello.i -o hello.s     # compile: C becomes assembly
gcc -c hello.s -o hello.o     # assemble: assembly becomes an object file
gcc hello.o -o hello          # link: objects plus libraries become an executable

# in practice, one command, with the warnings turned up
gcc -std=c17 -Wall -Wextra -Wpedantic -g -O2 hello.c -o hello

Reading compiler and linker output

$ gcc -Wall -Wextra -c demo.c
demo.c: In function 'main':
demo.c:12:13: warning: format '%d' expects argument of type 'int', but argument 2
             has type 'const char *' [-Wformat=]
demo.c:20:5: error: 'count' undeclared (first use in this function)

# linker errors name symbols, not lines
$ gcc main.o util.o -o app
/usr/bin/ld: main.o: in function 'main':
main.c:(.text+0x2a): undefined reference to 'helper'
collect2: error: ld returned 1 exit status

Full lesson: Syntax and the compiled toolchain →

Pointers and memory

Allocating and freeing

#include <stdlib.h>
#include <string.h>

size_t n = 1000;
int *buf = malloc(n * sizeof *buf);   /* sizeof *buf, not sizeof(int) */
if (buf == NULL) {
    return EXIT_FAILURE;              /* allocation failed: nothing to free */
}
memset(buf, 0, n * sizeof *buf);
/* ... use buf ... */
free(buf);
buf = NULL;                           /* makes a later double free harmless */

Allocating and freeing

/* the realloc trap: assigning straight back loses the old block on failure */
int *grown = realloc(buf, 2000 * sizeof *buf);
if (grown == NULL) {
    free(buf);                  /* buf is still valid and still yours to free */
    return EXIT_FAILURE;
}
buf = grown;

Strings and buffers

char dst[8];

strcpy(dst, "123456789");            /* writes 10 bytes into 8: undefined behaviour */

strncpy(dst, src, sizeof dst - 1);   /* bounded, but may leave no terminator */
dst[sizeof dst - 1] = '\0';          /* so terminate it yourself */

snprintf(dst, sizeof dst, "%s-%d", src, 7);   /* truncates safely, always terminates */

/* strlen walks bytes until the terminator, so it needs a terminated buffer */
size_t len = strlen(dst);

Full lesson: Pointers and memory →

Structs, files and undefined behaviour

Structs

/* returning a struct by value copies it, so the result is safe to use */
struct point midpoint(struct point a, struct point b) {
    struct point m = { (a.x + b.x) / 2.0, (a.y + b.y) / 2.0 };
    return m;
}

/* structs are compared member by member; == does not compile for them */
if (r1.id == r2.id && strcmp(r1.name, r2.name) == 0) { /* equal */ }

Undefined behaviour

# make these visible instead of silent
gcc -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer demo.c -o demo
./demo
# AddressSanitizer: heap-buffer-overflow on address 0x602000000014
# runtime error: signed integer overflow: 2147483647 + 1 cannot be represented

Full lesson: Structs, files and undefined behaviour →

Setting up a C toolchain: compiler, make and gdb

Getting a compiler and choosing a standard

# check what you actually have
cc --version
gcc --version
clang --version
make --version
gdb --version

# Debian and Ubuntu
sudo apt install build-essential gdb valgrind

# macOS: clang arrives with the command line tools
xcode-select --install

Getting a compiler and choosing a standard

gcc -std=c17 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror -g -O0 main.c -o app

Running under gdb

gcc -std=c17 -Wall -Wextra -g -O0 main.c -o app
gdb ./app

# inside gdb
(gdb) break main
(gdb) run
(gdb) next          # step over
(gdb) step          # step into
(gdb) print i
(gdb) backtrace
(gdb) continue
(gdb) quit

Full lesson: Setting up a C toolchain: compiler, make and gdb →

Arrays, strings and the string library

Strings and their pitfalls

char a[] = "hello";      /* 6 bytes, mutable, writable copy */
char *b  = "hello";      /* pointer to read-only literal: do not modify */
const char *c = "hello"; /* the honest declaration */

/* b[0] = 'H';  undefined behaviour, often a segfault */

Full lesson: Arrays, strings and the string library →

Dynamic memory patterns and allocation bugs

The four bugs valgrind finds

# sanitizers first: fast and precise
cc -std=c17 -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer app.c -o app
./app

# valgrind when you cannot recompile, or want leak accounting
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./app
valgrind --tool=helgrind ./threaded_app   # race detection

Full lesson: Dynamic memory patterns and allocation bugs →

Preprocessor, headers and multi-file projects

Macros and their traps

/* prefer these */
enum { MAX_ITEMS = 16 };            /* a real type-checked constant */
static const double PI = 3.14159265358979;
static inline int square(int x) { return x * x; }

/* use a macro only when you need the type or the caller's scope */
#define ARRAY_LEN(a)  (sizeof (a) / sizeof (a)[0])   /* arrays only, not pointers */
#define MAX(a, b)     ((a) > (b) ? (a) : (b))        /* arguments parenthesised */

Macros and their traps

#define LOG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
#define CHECK(cond, ...) do { if (!(cond)) { LOG("check failed: " #cond, __VA_ARGS__); } } while (0)

Full lesson: Preprocessor, headers and multi-file projects →

Building and linking: static and shared libraries

Object files and symbols

cc -std=c17 -Wall -Wextra -c mathx.c -o mathx.o

nm mathx.o            # T = defined text, U = undefined, D = data
nm -C mathx.o         # demangle C++ names
objdump -d mathx.o    # disassembly
readelf -h mathx.o    # ELF header, architecture and type

# why a symbol is missing
nm -u main.o          # everything main.o still needs

pkg-config and diagnosing link failures

pkg-config --cflags --libs libcurl     # -> -I... -lcurl
cc main.c $(pkg-config --cflags --libs libcurl) -o app

# typical failures and their real meaning
# undefined reference to 'sqrt'        -> add -lm
# cannot find -lmylib                  -> -L path wrong or library not built
# relocation R_X86_64_PC32 ... recompile with -fPIC
# duplicate symbol                     -> two strong definitions, often a header definition
# version GLIBC_2.34 not found         -> binary built on a newer distribution

Full lesson: Building and linking: static and shared libraries →

Debugging with gdb, sanitizers and valgrind

Core dumps and post-mortem debugging

ulimit -c unlimited                      # allow core files
cat /proc/sys/kernel/core_pattern         # where they land

gdb ./app core
(gdb) backtrace
(gdb) frame 0
(gdb) info registers
(gdb) print *(struct Conn *)arg

Full lesson: Debugging with gdb, sanitizers and valgrind →

Portability, standards and disciplined C

Undefined, unspecified and implementation-defined

/* all of these are undefined behaviour */
int x = INT_MAX + 1;             /* signed overflow */
int a[4]; a[4] = 0;              /* one past the end */
p = malloc(8); free(p); *p = 1;  /* use after free */
i = i++ + 1;                     /* two unsequenced modifications */
shift = 1 << 32;                 /* shift >= the width of the type */
memcpy(dst, dst + 1, 10);        /* overlapping regions */

/* and these are merely unspecified, not UB */
printf("%d %d\n", f(), g());     /* argument evaluation order is unspecified */

Making the compiler your reviewer

CFLAGS := -std=c17 -O2 -g \
          -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion \
          -Wshadow -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
          -Wformat=2 -Wundef -Wvla -Wwrite-strings -Werror

# extra hardening for shipped binaries
cc $(CFLAGS) -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE -pie app.c -o app

# static analysis
clang --analyze app.c
cppcheck --enable=all --inconclusive app.c

Full lesson: Portability, standards and disciplined C →

FAQ

Is this C cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 10 lessons of the C course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full C course — it carries the worked explanations, the edge cases and the exercises behind every line here.

C++ C# Scala Lua Dart

Last refreshed 2026-09-27.