Skip to main content

Learning Resources

Cheatsheet

A complete C cheatsheet — every concept in one page: syntax, data types, operators, control flow, arrays, strings, functions, pointers, memory, structures, files, and the preprocessor. Ideal for last-minute revision and day-to-day lookup.

Quick Reference

C Programming Cheatsheet

Every concept of C on one page — syntax, tables, and the smallest working snippet for each idea. Built for revision the night before an exam or an interview, and for looking things up while you code.

Program Structure & Input / Output

Minimal program


#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}

Compile and run


gcc main.c -o app        # compile
gcc -Wall -Wextra main.c # with warnings on
gcc -E main.c            # stop after preprocessing
gcc -g main.c            # include debug symbols
./app                    # run

Output and input


printf("%d %5.2f %s %c\n", n, f, str, ch);
scanf("%d %f", &n, &f);       /* & required except for arrays */

puts(str);                        /* prints and adds \n     */
fgets(buf, sizeof buf, stdin);   /* safe line input        */
ch = getchar();  putchar(ch);   /* one character at a time */

Format specifiers

SpecTypeSpecType
%d / %iint%uunsigned int
%ldlong%lldlong long
%ffloat / double (printf)%lfdouble (scanf)
%cchar%sstring
%x / %ohex / octal%escientific
%ppointer%zusize_t
%%literal percent%gshortest float form

Width, precision, and flags


"%5d"     /* width 5, right aligned  */
"%-5d"    /* width 5, left aligned   */
"%05d"    /* pad with zeros          */
"%.2f"    /* 2 decimal places        */
"%8.3f"   /* width 8, 3 decimals     */
"%+d"     /* always show the sign    */

Escape sequences


\n  newline      \t  tab          \\  backslash
\r  carriage ret \0  null char    \"  double quote
\b  backspace    \a  bell         \'  single quote

Data Types, Variables & Constants

Sizes and ranges (typical 64-bit system)

TypeBytesRangeSpecifier
char1−128 to 127%c
unsigned char10 to 255%c / %u
short2−32,768 to 32,767%hd
int4−2,147,483,648 to 2,147,483,647%d
unsigned int40 to 4,294,967,295%u
long8*±9.2 × 1018%ld
long long8±9.2 × 1018%lld
float4~6–7 significant digits%f
double8~15–16 significant digits%lf
long double16*Extended precision%Lf

* long is 4 bytes on Windows. Always confirm with sizeof.

Declaring and qualifying


int a = 10, b = 20;
const float PI = 3.14f;    /* cannot be modified      */
volatile int flag;          /* may change externally   */
unsigned long total = 0UL;

enum { MAX = 100 };          /* typed, scoped constant  */
#define SIZE 50              /* textual constant        */

Literal suffixes and type conversion


10      int        10U    unsigned    10L   long
3.14    double     3.14f  float       0x1F  hex
017     octal      0b1010 binary (ext) 'A'  char

float avg = (float)sum / count;   /* explicit cast */
/* promotion order: char → int → long → float → double */

Operators

CategoryOperatorsNote
Arithmetic+ − * / %% is integers only
Relational== != > < >= <=Yield 1 or 0
Logical&& || !Short-circuit
Bitwise& | ^ ~ << >>Operate bit by bit
Assignment= += −= *= /= %= &= |= ^= <<= >>=Right to left
Unary++ −− + − ! ~ & * sizeofRight to left
Conditional? :The only ternary
Comma,Lowest precedence
Member. -> [] ()Highest precedence

Precedence — highest to lowest


 1. () [] . -> ++(post) --(post)      left → right
 2. ++(pre) --(pre) + - ! ~ * & sizeof (cast)   right → left
 3. * / %                             left → right
 4. + -                               left → right
 5. << >>                             left → right
 6. < <= > >=                         left → right
 7. == !=                             left → right
 8. &      9. ^      10. |             left → right
11. &&    12. ||                       left → right
13. ?:                                right → left
14. = += -= ...                       right → left
15. ,                                 left → right

Bit tricks


x & 1               /* odd if 1                  */
x << n              /* multiply by 2^n           */
x >> n              /* divide by 2^n             */
x | (1 << n)        /* set bit n                 */
x & ~(1 << n)       /* clear bit n               */
x ^ (1 << n)        /* toggle bit n              */
(x >> n) & 1        /* read bit n                */

Control Flow

Decisions


if (cond) {
    ...
} else if (other) {
    ...
} else {
    ...
}

max = (a > b) ? a : b;

switch (n) {
    case 1: ...; break;
    case 2:
    case 3: ...; break;
    default: ...;
}

Loops


while (cond) {
    ...
}

do {
    ...
} while (cond);   /* ; needed */

for (i = 0; i < n; i++) {
    ...
}

for (;;) { ... }   /* infinite */

break;      /* exit loop      */
continue;   /* next iteration */
LoopCondition testedMinimum runsBest for
whileBefore body0Unknown count
do-whileAfter body1Menus, retry prompts
forBefore body0Known count

Arrays


int a[5];                        /* uninitialised          */
int b[5] = {1, 2, 3, 4, 5};
int c[5] = {1, 2};             /* rest are 0             */
int d[5] = {0};                /* all zeros              */
int e[]  = {1, 2, 3};          /* size inferred = 3      */

int n = sizeof(b) / sizeof(b[0]);   /* element count */

2D arrays


int m[2][3] = { {1,2,3}, {4,5,6} };
m[1][2] = 9;

for (i = 0; i < 2; i++)
    for (j = 0; j < 3; j++)
        printf("%d ", m[i][j]);

/* Row-major: address of m[i][j] = base + (i*cols + j)*sizeof(int) */
/* As a parameter, all dimensions but the first are required:      */
void show(int m[][3], int rows);

Arrays decay to pointers when passed, so sizeof inside the function gives the pointer size. Always pass the element count separately. C does no bounds checking.

Strings — <string.h>


char s1[] = "hello";      /* modifiable, 6 bytes    */
char s2[20] = "hello";    /* room to grow           */
const char *s3 = "hello";  /* literal, do not modify */
FunctionDoesReturns
strlen(s)Length without '\0'size_t
strcpy(d, s)Copy s into dd
strncpy(d, s, n)Copy at most n charsd
strcat(d, s)Append s to dd
strncat(d, s, n)Append at most n charsd
strcmp(a, b)Compare<0, 0, >0
strncmp(a, b, n)Compare first n chars<0, 0, >0
strchr(s, c)First occurrence of cPointer or NULL
strrchr(s, c)Last occurrence of cPointer or NULL
strstr(s, sub)Find a substringPointer or NULL
strtok(s, delim)Split into tokensPointer or NULL
strcspn(s, "\n")Index of first matchsize_t
memset(p, c, n)Fill n bytes with cp
memcpy(d, s, n)Copy n bytesd

Common patterns


fgets(buf, sizeof buf, stdin);
buf[strcspn(buf, "\n")] = '\0';   /* strip newline    */

if (strcmp(a, b) == 0) ...           /* equal — never == */

scanf("%49s", name);                /* bound the width  */
scanf("%[^\n]", line);               /* read with spaces */

/* char classification — <ctype.h> */
isalpha isdigit isalnum isspace isupper islower toupper tolower

Never use gets() — removed in C11. Use fgets.

Functions & Recursion


int add(int a, int b);           /* prototype  */

int add(int a, int b) {         /* definition */
    return a + b;
}

int s = add(3, 4);              /* call       */

Call by value


void f(int x) {
    x = 99;   /* copy only */
}
f(a);        /* a unchanged */

Call by reference


void g(int *x) {
    *x = 99;  /* the original */
}
g(&a);       /* a becomes 99 */

Recursion and function pointers


int fact(int n) {
    if (n <= 1) return 1;      /* base case      */
    return n * fact(n - 1);      /* recursive case */
}

int (*fp)(int, int) = add;    /* function pointer */
int r = fp(3, 4);

typedef int (*Op)(int, int);   /* readable alias   */

Storage Classes, Scope & Memory

ClassStorageScopeLifetimeDefault value
autoStackBlockUntil block endsGarbage
registerRegister (hint)BlockUntil block endsGarbage
static (local)Data / BSSBlockWhole program0
static (global)Data / BSSOne file onlyWhole program0
externData / BSSAll filesWhole program0
Memory segmentHoldsManaged by
StackLocals, parameters, return addressesAutomatic
Heapmalloc / calloc allocationsYou
DataInitialised globals and staticsAutomatic
BSSUninitialised globals and statics (zeroed)Automatic
TextCompiled code, string literalsRead-only

void counter(void) {
    static int n = 0;   /* survives between calls */
    n++;
}

extern int shared;      /* defined in another file */
static int privateVar;  /* invisible to other files */

Pointers


int  a = 10;
int *p = &a;        /* & = address of        */
printf("%d", *p);   /* * = value at (deref)   */
*p = 20;             /* a is now 20            */
DeclarationMeaning
int *pPointer to int
int **ppPointer to a pointer
int *arr[5]Array of 5 pointers
int (*pa)[5]Pointer to an array of 5
int (*fp)(int)Pointer to a function
void *vGeneric pointer — cast before use
const int *pValue is const, pointer is not
int * const pPointer is const, value is not
const int * const pBoth are const

Arithmetic and array equivalence


p + 1       /* advances by sizeof(*p) bytes */
p2 - p1     /* number of elements between   */

a[i]  ==  *(a + i)  ==  *(i + a)  ==  i[a]
&a[i] ==  a + i

/* Legal: + - ++ -- comparison. Illegal: * / % on pointers */
Problem pointerCauseFix
NULLPoints at nothing by designCheck before dereferencing
WildNever initialisedInitialise to NULL
DanglingTarget freed or out of scopep = NULL; after free

Dynamic Memory — <stdlib.h>

FunctionSignatureInitialises?
mallocvoid *malloc(size_t bytes)No — garbage
callocvoid *calloc(size_t n, size_t size)Yes — zeros
reallocvoid *realloc(void *p, size_t bytes)Keeps old data
freevoid free(void *p)Releases the block

int *p = malloc(n * sizeof(*p));   /* sizeof(*p), not sizeof(int) */
if (p == NULL) { /* handle failure */ return 1; }

int *q = realloc(p, m * sizeof(*p));
if (q != NULL) p = q;             /* never assign directly */

free(p);
p = NULL;                            /* avoid dangling        */

Dynamic 2D array — one contiguous block


int *g = malloc(rows * cols * sizeof(*g));
g[i * cols + j] = 5;                /* manual indexing */
free(g);                                /* one free        */

Rules: one free per allocation, never free twice, free inner pointers before the structure that holds them, and free(NULL) is always safe.

Structures, Unions, Enums & typedef


struct Student {
    char  name[50];
    int   roll;
    float marks;
};                                    /* semicolon! */

struct Student s1 = { "Asha", 101, 88.5 };
struct Student s2 = { .roll = 102 };   /* designated */
struct Student s3 = s1;                /* copy ok    */

s1.roll          /* variable → dot   */
p->roll          /* pointer  → arrow */
Aspectstructunion
MemorySum of members + paddingLargest member only
Valid at onceAll membersOnly the last written
Use forRecords with many fieldsOne of several types

union Value { int i; float f; };

enum Day { MON, TUE, WED };        /* 0, 1, 2       */
enum St  { OK = 200, ERR = 500 };   /* explicit      */

typedef struct { int x, y; } Point;
Point pt = { 3, 5 };

struct Node { int d; struct Node *next; };  /* self-referential */

struct Flags { unsigned int on : 1; };      /* bit field        */

Structures can be assigned with = but not compared with ==. Pass large ones as const struct T *.

File Handling & Command Line

ModeExistsDoes not exist
"r"Read from startNULL
"w"Erases contentsCreates
"a"Writes at endCreates
"r+"Read and write, preservedNULL
"w+"Erases contentsCreates
"a+"Read anywhere, write at endCreates
+ bBinary mode — no newline translation

FILE *fp = fopen("data.txt", "r");
if (fp == NULL) { perror("data.txt"); return 1; }

while (fgets(line, sizeof line, fp) != NULL)   /* not feof! */
    fputs(line, stdout);

fclose(fp);
FunctionPurposeFunctionPurpose
fopenOpenfcloseFlush and close
fgetcRead a char (int!)fputcWrite a char
fgetsRead a linefputsWrite a string
fscanfFormatted readfprintfFormatted write
freadRead raw blocksfwriteWrite raw blocks
fseekMove positionftellCurrent offset
rewindBack to startfeofEnd reached
ferrorError occurredremoveDelete a file

fwrite(&s, sizeof s, 1, fp);    /* binary record out */
fread(&t, sizeof t, 1, fp);     /* binary record in  */

fseek(fp, 0L, SEEK_END);          /* SEEK_SET/CUR/END  */
long size = ftell(fp);            /* file size         */

int main(int argc, char *argv[]) {
    /* argv[0] = program, argv[1..] = args, argv[argc] = NULL */
    if (argc < 2) return 1;
    int n = atoi(argv[1]);          /* args are strings  */
}

Preprocessor Directives


#include <stdio.h>        /* system paths      */
#include "my.h"           /* local first       */

#define MAX 100            /* no semicolon!     */
#define SQ(x) ((x) * (x))  /* parenthesize all  */
#undef MAX

#ifdef DEBUG  ... #endif
#ifndef MAX    ... #endif
#if V == 1    ... #elif V == 2 ... #else ... #endif

#error "stop the build"
#pragma once             /* non-standard guard */

Include guard


#ifndef MYFILE_H
#define MYFILE_H
   ... declarations ...
#endif

Operators


#x       /* "x"     stringize */
a##b     /* ab      paste     */
defined(X)  /* in #if      */
\        /* continue line */

Predefined macros


__FILE__   __LINE__
__DATE__   __TIME__
__STDC__   __func__
_WIN32 __linux__ __APPLE__
__GNUC__   _MSC_VER

Multi-statement macro and variadic logging


#define SWAP(a, b) do { int t=(a); (a)=(b); (b)=t; } while (0)

#define LOG(fmt, ...) \
    fprintf(stderr, "[%s:%d] " fmt, __FILE__, __LINE__, __VA_ARGS__)

Standard Library Quick Reference

HeaderProvides
<stdio.h>printf, scanf, FILE, fopen, fgets, fread
<stdlib.h>malloc, free, atoi, rand, qsort, exit, abs
<string.h>strlen, strcpy, strcmp, strcat, memset, memcpy
<math.h>sqrt, pow, abs, ceil, floor, sin, log
<ctype.h>isdigit, isalpha, toupper, tolower
<time.h>time, clock, difftime, strftime
<limits.h>INT_MAX, INT_MIN, CHAR_BIT
<float.h>FLT_MAX, DBL_MAX, DBL_EPSILON
<assert.h>assert — disabled by NDEBUG
<errno.h>errno, used with perror / strerror
<stdbool.h>bool, true, false (C99)

Frequently used snippets


srand(time(NULL));  r = rand() % 100;   /* 0..99          */
qsort(arr, n, sizeof(*arr), cmp);       /* generic sort   */
n = atoi(str);   d = atof(str);          /* string→number  */
exit(0);                                    /* end program    */

Top Gotchas

WrongRightWhy
if (x = 5)if (x == 5)Assignment, always true
5 / 2 for 2.55.0 / 2Integer division truncates
scanf("%d", n)scanf("%d", &n)scanf needs an address
#define MAX 100;#define MAX 100Semicolon gets substituted
#define SQ(x) x*x((x)*(x))SQ(2+3) gives 11
s1 == s2 for stringsstrcmp(s1,s2)==0Compares addresses
char c = fgetc(fp)int c = fgetc(fp)EOF needs an int
while (!feof(fp))while (fgets(...))Processes last item twice
gets(buf)fgets(buf, sizeof buf, stdin)Buffer overflow
*p.memberp->memberDot binds tighter than *
struct1 == struct2Compare member by memberNot allowed in C
free(p) then use pfree(p); p = NULL;Dangling pointer
Missing break in switchAdd breakCases fall through
a[n] for size nLast index is n-1Out of bounds
fflush(stdin)Read and discard to \nUndefined behaviour
if (a = b) in a loopCompile with -WallWarnings catch most of these