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.
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
| Spec | Type | Spec | Type |
|---|---|---|---|
%d / %i | int | %u | unsigned int |
%ld | long | %lld | long long |
%f | float / double (printf) | %lf | double (scanf) |
%c | char | %s | string |
%x / %o | hex / octal | %e | scientific |
%p | pointer | %zu | size_t |
%% | literal percent | %g | shortest 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)
| Type | Bytes | Range | Specifier |
|---|---|---|---|
char | 1 | −128 to 127 | %c |
unsigned char | 1 | 0 to 255 | %c / %u |
short | 2 | −32,768 to 32,767 | %hd |
int | 4 | −2,147,483,648 to 2,147,483,647 | %d |
unsigned int | 4 | 0 to 4,294,967,295 | %u |
long | 8* | ±9.2 × 1018 | %ld |
long long | 8 | ±9.2 × 1018 | %lld |
float | 4 | ~6–7 significant digits | %f |
double | 8 | ~15–16 significant digits | %lf |
long double | 16* | 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
| Category | Operators | Note |
|---|---|---|
| Arithmetic | + − * / % | % is integers only |
| Relational | == != > < >= <= | Yield 1 or 0 |
| Logical | && || ! | Short-circuit |
| Bitwise | & | ^ ~ << >> | Operate bit by bit |
| Assignment | = += −= *= /= %= &= |= ^= <<= >>= | Right to left |
| Unary | ++ −− + − ! ~ & * sizeof | Right 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 */
| Loop | Condition tested | Minimum runs | Best for |
|---|---|---|---|
while | Before body | 0 | Unknown count |
do-while | After body | 1 | Menus, retry prompts |
for | Before body | 0 | Known 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 */
| Function | Does | Returns |
|---|---|---|
strlen(s) | Length without '\0' | size_t |
strcpy(d, s) | Copy s into d | d |
strncpy(d, s, n) | Copy at most n chars | d |
strcat(d, s) | Append s to d | d |
strncat(d, s, n) | Append at most n chars | d |
strcmp(a, b) | Compare | <0, 0, >0 |
strncmp(a, b, n) | Compare first n chars | <0, 0, >0 |
strchr(s, c) | First occurrence of c | Pointer or NULL |
strrchr(s, c) | Last occurrence of c | Pointer or NULL |
strstr(s, sub) | Find a substring | Pointer or NULL |
strtok(s, delim) | Split into tokens | Pointer or NULL |
strcspn(s, "\n") | Index of first match | size_t |
memset(p, c, n) | Fill n bytes with c | p |
memcpy(d, s, n) | Copy n bytes | d |
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
| Class | Storage | Scope | Lifetime | Default value |
|---|---|---|---|---|
auto | Stack | Block | Until block ends | Garbage |
register | Register (hint) | Block | Until block ends | Garbage |
static (local) | Data / BSS | Block | Whole program | 0 |
static (global) | Data / BSS | One file only | Whole program | 0 |
extern | Data / BSS | All files | Whole program | 0 |
| Memory segment | Holds | Managed by |
|---|---|---|
| Stack | Locals, parameters, return addresses | Automatic |
| Heap | malloc / calloc allocations | You |
| Data | Initialised globals and statics | Automatic |
| BSS | Uninitialised globals and statics (zeroed) | Automatic |
| Text | Compiled code, string literals | Read-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 */
| Declaration | Meaning |
|---|---|
int *p | Pointer to int |
int **pp | Pointer 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 *v | Generic pointer — cast before use |
const int *p | Value is const, pointer is not |
int * const p | Pointer is const, value is not |
const int * const p | Both 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 pointer | Cause | Fix |
|---|---|---|
| NULL | Points at nothing by design | Check before dereferencing |
| Wild | Never initialised | Initialise to NULL |
| Dangling | Target freed or out of scope | p = NULL; after free |
Dynamic Memory — <stdlib.h>
| Function | Signature | Initialises? |
|---|---|---|
malloc | void *malloc(size_t bytes) | No — garbage |
calloc | void *calloc(size_t n, size_t size) | Yes — zeros |
realloc | void *realloc(void *p, size_t bytes) | Keeps old data |
free | void 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 */
| Aspect | struct | union |
|---|---|---|
| Memory | Sum of members + padding | Largest member only |
| Valid at once | All members | Only the last written |
| Use for | Records with many fields | One 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
| Mode | Exists | Does not exist |
|---|---|---|
"r" | Read from start | NULL |
"w" | Erases contents | Creates |
"a" | Writes at end | Creates |
"r+" | Read and write, preserved | NULL |
"w+" | Erases contents | Creates |
"a+" | Read anywhere, write at end | Creates |
+ b | Binary 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);
| Function | Purpose | Function | Purpose |
|---|---|---|---|
fopen | Open | fclose | Flush and close |
fgetc | Read a char (int!) | fputc | Write a char |
fgets | Read a line | fputs | Write a string |
fscanf | Formatted read | fprintf | Formatted write |
fread | Read raw blocks | fwrite | Write raw blocks |
fseek | Move position | ftell | Current offset |
rewind | Back to start | feof | End reached |
ferror | Error occurred | remove | Delete 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
| Header | Provides |
|---|---|
<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
| Wrong | Right | Why |
|---|---|---|
if (x = 5) | if (x == 5) | Assignment, always true |
5 / 2 for 2.5 | 5.0 / 2 | Integer division truncates |
scanf("%d", n) | scanf("%d", &n) | scanf needs an address |
#define MAX 100; | #define MAX 100 | Semicolon gets substituted |
#define SQ(x) x*x | ((x)*(x)) | SQ(2+3) gives 11 |
s1 == s2 for strings | strcmp(s1,s2)==0 | Compares 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.member | p->member | Dot binds tighter than * |
struct1 == struct2 | Compare member by member | Not allowed in C |
free(p) then use p | free(p); p = NULL; | Dangling pointer |
Missing break in switch | Add break | Cases fall through |
a[n] for size n | Last index is n-1 | Out of bounds |
fflush(stdin) | Read and discard to \n | Undefined behaviour |
if (a = b) in a loop | Compile with -Wall | Warnings catch most of these |