C Basics Cheatsheet
Cheatsheet · 28 Sep 2026
AI-generated Written with AI, solely for personal reference.
C is a small, fast language that sits close to the hardware: you manage memory yourself, and the compiler trusts you. Snippets without a main go inside int main(void) { ... } with #include <stdio.h> at the top.
Compile and run
cc hello.c -o hello # compile (cc is gcc or clang)
./hello # run
cc -Wall -Wextra -g hello.c -o hello # show warnings, add debug info
cc -fsanitize=address -g app.c -o app # catch memory bugs at runtime
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0; /* 0 means success */
}
Every statement ends with ;. Blocks use { }. Comments are /* ... */ or // ....
Types and printf formats
| Type | Holds | Format |
|---|---|---|
int |
Whole number | %d |
long |
Larger whole number | %ld |
unsigned int |
Non-negative whole number | %u |
float |
Decimal (about 7 digits) | %f |
double |
Decimal (about 15 digits) | %f (%.2f for 2 places) |
char |
One character | %c |
char[] / char * |
String | %s |
size_t |
Sizes and lengths | %zu |
| pointer | Memory address | %p |
int age = 30;
double price = 9.5;
char grade = 'A'; /* single quotes for a char */
const int MAX = 100; /* can't be changed */
printf("%d %.2f %c %d\n", age, price, grade, MAX); /* 30 9.50 A 100 */
printf("int is %zu bytes\n", sizeof(int)); /* usually 4 */
Variables aren’t set to zero automatically: always give them a value before use. bool needs #include <stdbool.h> (before C23).
Operators
printf("%d %d\n", 7 / 2, 7 % 2); /* 3 1: int division drops the decimals */
printf("%.1f\n", 7 / 2.0); /* 3.5: one side is a double */
printf("%.1f\n", (double)7 / 2); /* 3.5: cast before dividing */
int n = 5;
n += 2; /* 7 */
n++; /* 8 */
printf("%d %d %d\n", n > 5 && n < 10, n == 8, !0); /* 1 1 1 (true is 1) */
Control flow
int score = 72;
if (score >= 80) {
printf("A\n");
} else if (score >= 60) {
printf("B\n");
} else {
printf("C\n");
}
for (int i = 0; i < 3; i++) {
printf("%d ", i); /* 0 1 2 */
}
printf("\n");
int count = 3;
while (count > 0) {
count--;
}
int day = 2;
switch (day) {
case 1: printf("Mon\n"); break;
case 2: printf("Tue\n"); break; /* without break, it falls through */
default: printf("Other\n");
}
break leaves a loop; continue skips to its next round.
Functions
Declare (prototype) a function before using it, or define it above main.
#include <stdio.h>
int add(int a, int b); /* prototype */
void greet(const char *name) { /* void: returns nothing */
printf("Hello, %s!\n", name);
}
int main(void) {
printf("%d\n", add(2, 3)); /* 5 */
greet("Maxine");
return 0;
}
int add(int a, int b) {
return a + b;
}
Arguments are copied into the function. To let a function change a caller’s variable, pass a pointer (below).
Arrays
int nums[5] = {10, 20, 30, 40, 50};
nums[0] = 11; /* indexes start at 0 */
size_t len = sizeof(nums) / sizeof(nums[0]); /* 5: only works on real arrays */
int total = 0;
for (size_t i = 0; i < len; i++) {
total += nums[i];
}
printf("%zu items, total %d\n", len, total); /* 5 items, total 151 */
int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
printf("%d\n", grid[1][2]); /* 6 */
C does not check bounds: nums[5] compiles, then reads memory that isn’t yours.
Strings
A string is a char array ending in '\0' (the null terminator).
#include <stdio.h>
#include <string.h>
int main(void) {
char name[20] = "Maxine"; /* room for 19 chars + '\0' */
char copy[20];
printf("%zu\n", strlen(name)); /* 6 (the '\0' isn't counted) */
strcpy(copy, name); /* copy (dest must be big enough) */
strcat(copy, "!"); /* append */
printf("%s\n", copy); /* Maxine! */
if (strcmp(name, "Maxine") == 0) { /* compare with strcmp, not == */
printf("match\n");
}
char msg[32];
snprintf(msg, sizeof msg, "age=%d", 30); /* safe formatting into a buffer */
printf("%s\n", msg); /* age=30 */
return 0;
}
Pointers
A pointer holds the memory address of another value.
#include <stdio.h>
void swap(int *a, int *b) { /* receives addresses */
int tmp = *a; /* * reads the value at the address */
*a = *b;
*b = tmp;
}
int main(void) {
int x = 1, y = 2;
int *p = &x; /* & takes an address */
*p = 10; /* changes x through the pointer */
printf("%d\n", x); /* 10 */
swap(&x, &y);
printf("%d %d\n", x, y); /* 2 10 */
int arr[3] = {5, 6, 7};
int *q = arr; /* an array name acts as a pointer to its first item */
printf("%d %d\n", *(q + 1), q[2]); /* 6 7: pointer arithmetic */
int *nothing = NULL; /* points nowhere; never dereference it */
if (nothing == NULL) printf("null\n");
return 0;
}
| Syntax | Meaning |
|---|---|
int *p |
p is a pointer to an int |
&x |
Address of x |
*p |
Value at the address in p |
p->field |
Field of the struct p points to (same as (*p).field) |
Structs
#include <stdio.h>
#include <string.h>
typedef struct {
char name[20];
int age;
} Person;
void birthday(Person *p) {
p->age++; /* -> through a pointer */
}
int main(void) {
Person a = {"Aisha", 29};
Person b;
strcpy(b.name, "Ali"); /* . on the struct itself */
b.age = 35;
birthday(&a);
printf("%s is %d\n", a.name, a.age); /* Aisha is 30 */
printf("%s is %d\n", b.name, b.age); /* Ali is 35 */
return 0;
}
Dynamic memory
Use the heap when the size is only known at runtime. Every malloc needs a matching free.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t n = 5;
int *nums = malloc(n * sizeof *nums); /* room for 5 ints */
if (nums == NULL) {
return 1; /* allocation failed */
}
for (size_t i = 0; i < n; i++) {
nums[i] = (int)(i * i);
}
int *bigger = realloc(nums, 10 * sizeof *nums); /* grow to 10 */
if (bigger == NULL) {
free(nums);
return 1;
}
nums = bigger;
printf("%d\n", nums[4]); /* 16 */
free(nums); /* give the memory back */
nums = NULL; /* avoid using it after free */
return 0;
}
Splitting code into files
/* math_utils.h: declarations */
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int square(int x);
#endif
/* math_utils.c: definitions */
#include "math_utils.h"
int square(int x) { return x * x; }
/* main.c */
#include <stdio.h>
#include "math_utils.h"
int main(void) { printf("%d\n", square(4)); return 0; }
cc main.c math_utils.c -o app
Classic mistakes
| Mistake | What goes wrong |
|---|---|
if (x = 5) |
Assigns instead of compares; use == |
| Using a variable before setting it | It holds garbage |
arr[len] in a loop |
Off by one: the last index is len - 1 |
strcpy into a small buffer |
Overflows memory; size buffers carefully, prefer snprintf |
== on strings |
Compares addresses; use strcmp |
Forgetting free |
Memory leak |
Using memory after free |
Crashes or silent corruption |
| Returning a pointer to a local variable | It disappears when the function returns |
Missing break in switch |
Falls through into the next case |
Compile with -Wall -Wextra to catch many of these, and -fsanitize=address to catch memory errors while the program runs.