Appendix A: C Standard Library Quick Reference

This appendix covers the most important C standard library functions for systems programming, organized by header. Each entry lists the signature, purpose, and common pitfalls.

stdio.h -- Standard I/O

FunctionSignaturePurpose
printfint printf(const char *fmt, ...)Print formatted output to stdout
fprintfint fprintf(FILE *stream, const char *fmt, ...)Print to any stream
snprintfint snprintf(char *buf, size_t n, const char *fmt, ...)Safe formatted string
scanfint scanf(const char *fmt, ...)Read formatted input from stdin
fopenFILE *fopen(const char *path, const char *mode)Open a file stream
fcloseint fclose(FILE *stream)Close a file stream
freadsize_t fread(void *ptr, size_t size, size_t n, FILE *s)Binary read
fwritesize_t fwrite(const void *ptr, size_t size, size_t n, FILE *s)Binary write
fgetschar *fgets(char *s, int n, FILE *stream)Read a line (safe)
fputsint fputs(const char *s, FILE *stream)Write a string
fseekint fseek(FILE *stream, long offset, int whence)Seek in stream
ftelllong ftell(FILE *stream)Current position
fflushint fflush(FILE *stream)Flush output buffer
perrorvoid perror(const char *s)Print errno message
feofint feof(FILE *stream)Check end-of-file
ferrorint ferror(FILE *stream)Check stream error

Pitfalls:

  • sprintf has no bounds checking. Always use snprintf.
  • gets is removed from C11. Never use it. Use fgets.
  • scanf("%s", buf) has no bounds checking. Use scanf("%63s", buf) with a width specifier.
  • feof returns true only after a read attempt fails. Don't use it as a loop condition before reading.
  • fclose on an already-closed FILE* is undefined behavior.

stdlib.h -- General Utilities

FunctionSignaturePurpose
mallocvoid *malloc(size_t size)Allocate memory
callocvoid *calloc(size_t n, size_t size)Allocate zeroed memory
reallocvoid *realloc(void *ptr, size_t size)Resize allocation
freevoid free(void *ptr)Free memory
exitvoid exit(int status)Terminate process
atexitint atexit(void (*fn)(void))Register exit handler
atoiint atoi(const char *s)String to int (unsafe)
strtollong strtol(const char *s, char **end, int base)String to long (safe)
strtoulunsigned long strtoul(const char *s, char **end, int base)String to unsigned long
strtoddouble strtod(const char *s, char **end)String to double
absint abs(int n)Absolute value
randint rand(void)Pseudo-random integer
srandvoid srand(unsigned seed)Seed random generator
qsortvoid qsort(void *base, size_t n, size_t size, int(*cmp)(...))Sort array
bsearchvoid *bsearch(const void *key, const void *base, ...)Binary search
getenvchar *getenv(const char *name)Get environment variable
systemint system(const char *cmd)Run shell command

Pitfalls:

  • atoi returns 0 on error, which is indistinguishable from converting "0". Use strtol instead.
  • realloc(ptr, 0) behavior is implementation-defined. Don't rely on it.
  • realloc on failure returns NULL but doesn't free the original. Save the original pointer: tmp = realloc(ptr, n); if (tmp) ptr = tmp;
  • rand() is not cryptographically secure. Use getrandom() for security.
  • system() is a shell injection risk. Avoid in production code.

string.h -- String and Memory Operations

FunctionSignaturePurpose
strlensize_t strlen(const char *s)String length
strcpychar *strcpy(char *dst, const char *src)Copy string (unsafe)
strncpychar *strncpy(char *dst, const char *src, size_t n)Copy with limit
strcatchar *strcat(char *dst, const char *src)Concatenate (unsafe)
strncatchar *strncat(char *dst, const char *src, size_t n)Concatenate with limit
strcmpint strcmp(const char *a, const char *b)Compare strings
strncmpint strncmp(const char *a, const char *b, size_t n)Compare n bytes
strchrchar *strchr(const char *s, int c)Find char in string
strrchrchar *strrchr(const char *s, int c)Find char (from end)
strstrchar *strstr(const char *haystack, const char *needle)Find substring
strtokchar *strtok(char *s, const char *delim)Tokenize (modifies string)
memcpyvoid *memcpy(void *dst, const void *src, size_t n)Copy memory (no overlap)
memmovevoid *memmove(void *dst, const void *src, size_t n)Copy memory (overlap ok)
memsetvoid *memset(void *s, int c, size_t n)Fill memory
memcmpint memcmp(const void *a, const void *b, size_t n)Compare memory
strerrorchar *strerror(int errnum)Error number to string

Pitfalls:

  • strncpy does NOT null-terminate if src is longer than n. Always: strncpy(dst, src, n-1); dst[n-1] = '\0';
  • memcpy with overlapping regions is undefined behavior. Use memmove.
  • strtok uses a static buffer and is not thread-safe. Use strtok_r.
  • strcmp returns 0 for equal strings (not 1). The return value is the difference, not a boolean.

math.h -- Mathematics

FunctionSignaturePurpose
sqrtdouble sqrt(double x)Square root
powdouble pow(double base, double exp)Power
fabsdouble fabs(double x)Absolute value
ceildouble ceil(double x)Round up
floordouble floor(double x)Round down
rounddouble round(double x)Round to nearest
logdouble log(double x)Natural logarithm
log10double log10(double x)Base-10 logarithm
sin/cos/tandouble sin(double x)Trig functions (radians)

Pitfalls:

  • Link with -lm on Linux. Math functions are in libm, not libc.
  • sqrt(-1) returns NaN, not an error. Check isnan().

ctype.h -- Character Classification

FunctionPurposeExample
isalpha(c)Letter?isalpha('A') = true
isdigit(c)Digit?isdigit('5') = true
isalnum(c)Letter or digit?
isspace(c)Whitespace?isspace(' ') = true
isupper(c) / islower(c)Case check
toupper(c) / tolower(c)Case conversion

Pitfalls:

  • Argument must be unsigned char or EOF. Passing a signed char with negative value is undefined behavior: isalpha((unsigned char)c).

errno.h -- Error Numbers

Common errno values:

ValueNameMeaning
1EPERMOperation not permitted
2ENOENTNo such file or directory
5EIOI/O error
9EBADFBad file descriptor
11EAGAINTry again (non-blocking)
12ENOMEMOut of memory
13EACCESPermission denied
17EEXISTFile exists
22EINVALInvalid argument
28ENOSPCNo space left on device
32EPIPEBroken pipe

Pitfalls:

  • errno is only valid immediately after a failed call. Successful calls may or may not reset it.
  • errno is thread-local in glibc (actually a macro that expands to (*__errno_location())).

signal.h -- Signal Handling

FunctionSignaturePurpose
signalvoid (*signal(int sig, void (*handler)(int)))(int)Set signal handler
raiseint raise(int sig)Send signal to self
killint kill(pid_t pid, int sig)Send signal to process
sigactionint sigaction(int sig, const struct sigaction *act, ...)Set handler (preferred)
sigprocmaskint sigprocmask(int how, const sigset_t *set, ...)Block/unblock signals

Pitfalls:

  • signal() behavior varies across systems. Use sigaction() instead.
  • Signal handlers must only call async-signal-safe functions. No printf, no malloc.

time.h -- Time Functions

FunctionSignaturePurpose
timetime_t time(time_t *tloc)Current time (seconds)
clockclock_t clock(void)CPU time used
difftimedouble difftime(time_t t1, time_t t0)Time difference
localtimestruct tm *localtime(const time_t *t)Convert to local time
gmtimestruct tm *gmtime(const time_t *t)Convert to UTC
strftimesize_t strftime(char *s, size_t max, const char *fmt, ...)Format time string
clock_gettimeint clock_gettime(clockid_t id, struct timespec *tp)High-resolution time

Pitfalls:

  • localtime returns a pointer to a static buffer (not thread-safe). Use localtime_r.
  • clock() measures CPU time, not wall time. Use clock_gettime(CLOCK_MONOTONIC) for benchmarks.

unistd.h -- POSIX System Interface

FunctionSignaturePurpose
readssize_t read(int fd, void *buf, size_t count)Read from fd
writessize_t write(int fd, const void *buf, size_t count)Write to fd
closeint close(int fd)Close fd
lseekoff_t lseek(int fd, off_t offset, int whence)Seek in fd
forkpid_t fork(void)Create child process
exec*int execvp(const char *file, char *const argv[])Replace process
pipeint pipe(int pipefd[2])Create pipe
dup2int dup2(int oldfd, int newfd)Duplicate fd
getpidpid_t getpid(void)Current PID
getcwdchar *getcwd(char *buf, size_t size)Current directory
sleepunsigned sleep(unsigned seconds)Sleep
usleepint usleep(useconds_t usec)Sleep (microseconds)
unlinkint unlink(const char *path)Delete file
accessint access(const char *path, int mode)Check file access

Pitfalls:

  • read and write may transfer fewer bytes than requested (short reads/ writes). Always loop.
  • close can fail. Check the return value, especially for files opened with O_SYNC.
  • fork + exec is POSIX, not C standard. Use posix_spawn when possible.

sys/types.h -- System Data Types

TypePurpose
pid_tProcess ID
uid_t / gid_tUser/group ID
off_tFile offset
size_tUnsigned size
ssize_tSigned size (for error returns)
mode_tFile permissions
dev_tDevice number
ino_tInode number
time_tTime in seconds

Pitfalls:

  • size_t is unsigned. Subtracting two size_t values can wrap to a huge number. Use ssize_t or cast carefully.
  • off_t is 32-bit by default on 32-bit systems. Use _FILE_OFFSET_BITS=64 for large file support.