COMP2017 Systems Programming Cheatsheet
Compact reference — all 13 topics. Print / Save as PDF for a 2-page A4 reference card.
1 · Format Specifiers (printf / scanf)
| Spec | Type | Note |
|---|---|---|
| %d / %i | int (signed) | decimal |
| %u | unsigned int | decimal |
| %ld / %lu | long / unsigned long | |
| %f | float/double (printf) | 6 dec default |
| %lf | double (scanf only) | use %f for float |
| %e / %g | float/double | sci / shorter |
| %c | char | single char |
| %s | char * (string) | null-terminated |
| %p | void * (pointer) | hex address |
| %x / %o | unsigned int | hex / octal |
| %zu | size_t | sizeof results |
| %% | literal % |
/* width.precision flags */
printf("%8.2f", 3.14); // " 3.14"
printf("%-8d", 42); // "42 " left-align
printf("%05d", 42); // "00042" zero-pad
2 · Pointer Cheat Sheet
| Operation | Syntax |
|---|---|
| Declare pointer | int *p; |
| Address-of | p = &x; |
| Dereference (read) | val = *p; |
| Dereference (write) | *p = 42; |
| Pointer arithmetic | p++; p+2; p-q |
| Array via pointer | *(p+i) == p[i] |
| Null check | if (p != NULL) |
| Void pointer | void *v = malloc(n); |
| Pointer to pointer | int **pp = &p; |
/* Function pointer */
int (*fn)(int, int); // declaration
fn = add; // assign
result = fn(2, 3); // call
/* typedef version */
typedef int (*Op)(int,int);
3 · String Functions <string.h>
| Signature | Notes |
|---|---|
| strlen(s) | length excl. \0 |
| strcpy(dst,src) | unsafe — no bounds |
| strncpy(dst,src,n) | copies n bytes; may not null-terminate! |
| strcat(dst,src) | unsafe — no bounds |
| strncat(dst,src,n) | appends n chars + \0 |
| strcmp(a,b) | <0 / 0 / >0 |
| strncmp(a,b,n) | compare first n chars |
| strchr(s,c) | ptr to first c or NULL |
| strstr(hay,ndl) | ptr to first match or NULL |
| sprintf(buf,fmt,…) | write to string buf |
| sscanf(s,fmt,…) | parse from string |
| strtol(s,&end,base) | safe atoi; base 10/16/0=auto |
| strtod(s,&end) | safe atof → double |
| rand() | random [0,RAND_MAX]; seed: srand(time(NULL)) |
4 · Memory Functions
| Signature | Notes |
|---|---|
| malloc(size) | uninitialized; NULL on fail |
| calloc(n,size) | n*size, zero-initialized |
| realloc(ptr,size) | may move; assign to tmp first! |
| free(ptr) | ptr must be from malloc/calloc/realloc |
| memcpy(dst,src,n) | copy n bytes; no overlap allowed |
| memmove(dst,src,n) | overlap-safe copy |
| memset(ptr,val,n) | fill n bytes with val (byte) |
int *p = malloc(n * sizeof(int));
if (!p) { perror("malloc"); exit(1); }
/* … use p … */
free(p); p = NULL; // NULL after free!
5 · File I/O <stdio.h>
| Mode | Meaning |
|---|---|
| "r" | read; file must exist |
| "w" | write; create/truncate |
| "a" | append; create if absent |
| "r+" | read+write; must exist |
| "w+" | read+write; truncate |
| "b" | binary flag (e.g. "rb") |
- fopen(path, mode)
- Returns FILE* or NULL on error
- fclose(fp)
- Flush + close; returns 0 or EOF
- fread(buf,sz,n,fp)
- Read n items of sz bytes
- fwrite(buf,sz,n,fp)
- Write n items; returns items written
- fgets(buf,n,fp)
- Read line; keeps \n; null-terminates
- fputs(s,fp)
- Write string (no \n added)
- fprintf(fp,fmt,…)
- printf to file
- fscanf(fp,fmt,…)
- scanf from file
- fseek(fp,off,whence)
- SEEK_SET / SEEK_CUR / SEEK_END
- ftell(fp)
- Current byte offset
- feof(fp) / ferror(fp)
- Check EOF / error flag
6 · Process Syscalls
- pid_t fork(void)
- Create child. Returns child PID to parent, 0 to child, -1 on error.
- execvp(file, argv[]) / execve(path, argv, envp)
- Replace process image. Only returns on error (-1).
- pid_t wait(int *status)
- Wait for any child. Use
WIFEXITED(s),WEXITSTATUS(s). - pid_t waitpid(pid, &status, opts)
- Wait for specific child. opts: 0 (block) or
WNOHANG(non-blocking). - getpid() / getppid()
- Current PID / parent PID.
- exit(status) / _exit(status)
exitflushes buffers;_exitdoes not (use in child after fork).- kill(pid, sig)
- Send signal to process.
kill(pid, SIGTERM)to terminate politely. - signal(signum, handler)
- Install signal handler. Prefer
sigaction()for portability.
pid_t pid = fork();
if (pid == 0) {
execvp("ls", args); _exit(1);
} else {
waitpid(pid, &status, 0);
}
7 · Low-level I/O (file descriptors)
- open(path, flags [, mode])
- Flags:
O_RDONLY O_WRONLY O_RDWR O_CREAT O_TRUNC O_APPEND. Returns fd or -1. - read(fd, buf, count)
- Returns bytes read (0 = EOF, -1 = error). May return less than count (short read).
- write(fd, buf, count)
- Returns bytes written or -1. Loop if short write needed.
- close(fd)
- Always close every fd. Returns 0 or -1.
- lseek(fd, offset, whence)
SEEK_SET/SEEK_CUR/SEEK_END. Returns new offset.- dup(fd)
- Copy fd to lowest available number.
- dup2(oldfd, newfd)
- Copy oldfd to newfd; closes newfd first. Used to redirect stdio.
/* Redirect stdout to file */
int fd = open("out.txt", O_WRONLY|O_CREAT, 0644);
dup2(fd, STDOUT_FILENO);
close(fd);
8 · Signals
| Signal | Cause / Default |
|---|---|
| SIGINT (2) | Ctrl+C → terminate |
| SIGTERM (15) | polite kill → terminate |
| SIGKILL (9) | force kill → cannot catch/ignore |
| SIGSEGV (11) | bad memory access → core dump |
| SIGCHLD (17) | child stopped/exited → ignore |
| SIGPIPE (13) | write to closed pipe → terminate |
| SIGALRM (14) | alarm() timer expired → terminate |
/* Simple handler */
void handler(int sig) { cleanup(); exit(0); }
signal(SIGINT, handler);
/* Robust (sigaction) */
struct sigaction sa = {0};
sa.sa_handler = handler;
sigaction(SIGINT, &sa, NULL);
9 · pthreads <pthread.h>
- pthread_create(&tid, NULL, fn, arg)
- Create thread running
fn(arg). Returns 0 on success. - pthread_join(tid, &retval)
- Wait for thread; retrieve return value. Must join or detach every thread.
- pthread_exit(retval)
- Terminate calling thread (does not kill process).
- pthread_mutex_init(&mtx, NULL)
- Initialise mutex (or use
PTHREAD_MUTEX_INITIALIZER). - pthread_mutex_lock(&mtx) / unlock
- Lock blocks if held; unlock releases. Always unlock every lock path.
- pthread_mutex_destroy(&mtx)
- Free mutex resources when no longer needed.
- sem_init(&sem, 0, val)
- Init semaphore (0 = thread-shared, val = initial count).
- sem_wait(&sem) / sem_post(&sem)
- Decrement (blocks at 0) / increment + wake one waiter.
- sem_destroy(&sem)
- Free semaphore. Link with
-lpthread. - pthread_rwlock_t rw
pthread_rwlock_rdlock(&rw)— shared read lock;pthread_rwlock_wrlock(&rw)— exclusive write lock;pthread_rwlock_unlock(&rw)— release.- pthread_cond_t cv
pthread_cond_wait(&cv, &m)— atomically release mutex & sleep;pthread_cond_signal(&cv)— wake one waiter;pthread_cond_broadcast(&cv)— wake all.
10 · Makefile Patterns
# Variables
CC = gcc
CFLAGS = -Wall -Wextra -g
OBJS = main.o utils.o
# Rule: target : prerequisites
prog: $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c # pattern rule
$(CC) $(CFLAGS) -c -o $@ $<
# Automatic variables
# $@ — target name
# $< — first prerequisite
# $^ — all prerequisites
# $* — stem (matched by %)
.PHONY: clean test
clean:
rm -f $(OBJS) prog
test: prog
./prog | diff - expected.txt
11 · GDB Commands
| Command | Action |
|---|---|
| break main | breakpoint at function / line |
| break file.c:42 | breakpoint at specific line |
| run [args] | start / restart program |
| next (n) | step over one line |
| step (s) | step into function call |
| continue (c) | continue to next breakpoint |
| print expr (p) | evaluate & print expression |
| x/4xw &var | examine memory (4 words, hex) |
| backtrace (bt) | show call stack |
| info locals | list local variables |
| watch var | break when var changes |
| list (l) | show source around current line |
| quit (q) | exit gdb |
gcc -g -o prog main.c # -g required!
gdb ./prog
(gdb) break main
(gdb) run
(gdb) print argv[0]
(gdb) backtrace
12 · Valgrind — Memcheck
valgrind \
--leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
--verbose \
./prog arg1 arg2
| Category | Meaning |
|---|---|
| definitely lost | no pointer to block — real leak |
| indirectly lost | only reachable via lost block |
| still reachable | pointed to at exit — often OK |
| Invalid read/write | out of bounds or freed memory |
| Uninit value | using uninitialized memory |
- Always compile with
-gfor file/line info - Use
--error-exitcode=1in test scripts - ~10–50× slower than normal execution
13 · Common Pitfalls
- Missing null terminator:
char buf[5]="hello"— no room for\0 - scanf without &:
scanf("%d", x)— must be&x - %f vs %lf in scanf: use
%lffordouble;%fforfloat - Double free: calling
free(p)twice corrupts the heap - Dangling pointer: using
pafterfree(p)— setp=NULL - Not closing pipe ends: forgetting to close unused pipe fds causes
read()to never see EOF - Zombie processes: forgetting to
waitpid()after child exits - Not checking malloc:
mallocreturns NULL on failure — always check - Integer overflow:
intwraps silently — uselongor check bounds - getchar() as char: store in
int, notchar— EOF (-1) truncated - Array decay in sizeof:
sizeof(arr)inside function gets pointer size, not array size - Race condition: reading shared data without a lock — always use mutex around shared state
- Deadlock via wrong lock order: always acquire multiple mutexes in the same global order
- exec after fork — double flush: use
_exit()notexit()in child to avoid flushing parent's buffers - Off-by-one in strncpy: if
n == strlen(src), null terminator is not copied — add 1 or manually set last byte to\0 - Signed/unsigned comparison: comparing
intandsize_t— compiler may warn; cast appropriately
14 · Math Library <math.h>
| Function | Notes |
|---|---|
| sqrt(x) | square root |
| pow(x,y) | x to the power y |
| fabs(x) | absolute value (double) |
| floor(x) | round down |
| ceil(x) | round up |
| round(x) | round to nearest integer |
| log(x) | natural log (ln) |
| log2(x) | base-2 logarithm |
| exp(x) | e^x |
| sin(x) / cos(x) / tan(x) | trig (radians) |
| M_PI | 3.14159… (define _USE_MATH_DEFINES on MSVC) |
| INFINITY / NAN | IEEE special values |
- Link with
-lm(e.g.gcc main.c -lm)
15 · Character Functions <ctype.h>
| Function | True when… |
|---|---|
| isalpha(c) | letter (a–z, A–Z) |
| isdigit(c) | digit (0–9) |
| isalnum(c) | letter or digit |
| isspace(c) | whitespace (space, \t, \n, …) |
| isupper(c) | uppercase letter |
| islower(c) | lowercase letter |
| isprint(c) | printable character |
| toupper(c) | → uppercase equivalent |
| tolower(c) | → lowercase equivalent |
- All take
int c— cast char:(unsigned char)cfirst to avoid UB
16 · GCC Compiler Flags
| Flag(s) | Effect |
|---|---|
| -Wall -Wextra -Wpedantic | enable most warnings |
| -Werror | treat warnings as errors |
| -g | debug symbols (for gdb/valgrind) |
| -O0 / -O1 / -O2 / -O3 | optimization levels (0=none, 3=max) |
| -fsanitize=address | ASan — memory errors (heap/stack) |
| -fsanitize=memory | MSan — uninit reads (Clang only) |
| -fsanitize=thread | TSan — data races |
| -fsanitize=undefined | UBSan — undefined behaviour |
| -lm | link math library |
| -pthread | link pthreads + enable thread macros |
| -Wvla | warn on variable-length arrays |
| -std=c11 / -std=c2x | select C standard |
17 · IPC: fork + pipe pattern
int fd[2]; pipe(fd); // fd[0]=read, fd[1]=write
if (fork() == 0) {
close(fd[0]); // child: close read end
write(fd[1], "hi", 2);
close(fd[1]); _exit(0);
} else {
close(fd[1]); // parent: close write end
char buf[64];
read(fd[0], buf, sizeof(buf));
wait(NULL);
}
// ── Shared memory (POSIX) ──
// shm_open("/name", O_CREAT|O_RDWR, 0666) → fd
// ftruncate(fd, size)
// mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)
// munmap(ptr, size); shm_unlink("/name")