Cpointers_basics.c
Pointers: address-of, dereference, and pass-by-pointer
#include <stdio.h>
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void increment(int *p, int amount) {
*p += amount; /* modify caller's variable */
}
int main(void) {
int x = 10, y = 20;
int *p = &x; /* p stores the address of x */
printf("x = %d\n", x); /* 10 */
printf("*p = %d\n", *p); /* 10 — dereference */
*p = 99; /* modify x through the pointer */
printf("x = %d\n", x); /* 99 */
swap(&x, &y);
printf("x=%d y=%d\n", x, y); /* x=20 y=99 */
increment(&x, 5);
printf("x = %d\n", x); /* 25 */
/* Pointer arithmetic: p+1 advances by sizeof(int) */
int arr[] = {10, 20, 30, 40, 50};
int *ap = arr;
printf("%d %d %d\n", *ap, *(ap+1), *(ap+2)); /* 10 20 30 */
/* arr[i] == *(arr + i) */
printf("%d\n", *(arr + 3)); /* 40 */
return 0;
}Cdynamic_memory.c
Dynamic memory: malloc, realloc, free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
int n = 5;
/* malloc: allocate uninitialised memory */
int *arr = malloc(n * sizeof(int));
if (arr == NULL) { /* ALWAYS check — malloc can fail */
fprintf(stderr, "malloc failed\n");
return 1;
}
for (int i = 0; i < n; i++) arr[i] = i * i;
for (int i = 0; i < n; i++) printf("%d ", arr[i]); /* 0 1 4 9 16 */
printf("\n");
/* calloc: allocate and zero-initialise */
double *matrix = calloc(4 * 4, sizeof(double)); /* 4x4 zeros */
/* realloc: resize — NEVER realloc into same pointer (leak on failure) */
int *bigger = realloc(arr, 10 * sizeof(int));
if (bigger == NULL) {
free(arr); /* free original if realloc fails */
free(matrix);
return 1;
}
arr = bigger; /* arr may now point to a new location */
/* Always free and null the pointer */
free(arr); arr = NULL;
free(matrix); matrix = NULL;
return 0;
}Cstructs.c
Structs: definition, heap allocation, arrow operator
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[64];
int age;
double score;
} Student;
/* Pass pointer to avoid copying the whole struct */
void print_student(const Student *s) {
printf("%s (age %d): %.1f\n", s->name, s->age, s->score);
/* s->field == (*s).field */
}
void set_score(Student *s, double score) {
s->score = score;
}
Student *student_new(const char *name, int age) {
Student *s = malloc(sizeof(Student));
if (!s) return NULL;
strncpy(s->name, name, sizeof(s->name) - 1);
s->name[sizeof(s->name) - 1] = '\0'; /* ensure null termination */
s->age = age;
s->score = 0.0;
return s;
}
int main(void) {
/* Stack allocation */
Student alice = {"Alice", 20, 95.5};
print_student(&alice);
/* Heap allocation */
Student *bob = student_new("Bob", 22);
if (!bob) return 1;
set_score(bob, 87.0);
print_student(bob);
free(bob);
return 0;
}Cstrings.c
Safe string handling: snprintf, strncpy, strtol
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
/* snprintf: safe formatting — always null-terminates */
char buf[64];
int written = snprintf(buf, sizeof(buf), "Hello, %s! You are %d.", "Alice", 30);
printf("%s (wrote %d chars)\n", buf, written);
/* strncpy: limited copy — manually null-terminate */
char dst[16];
strncpy(dst, "Hello World!", sizeof(dst) - 1);
dst[sizeof(dst) - 1] = '\0';
printf("%s\n", dst);
/* String length: O(n) — walks to \0 */
size_t len = strlen(buf);
/* String comparison */
if (strcmp("abc", "abc") == 0) printf("equal\n");
if (strncmp("abc", "abcdef", 3) == 0) printf("first 3 match\n");
if (strcasecmp("Hello", "hello") == 0) printf("case-insensitive match\n");
/* Safe integer parsing */
char *numstr = " 42 ";
char *endptr;
long n = strtol(numstr, &endptr, 10);
if (endptr == numstr) {
fprintf(stderr, "no digits found\n");
} else {
printf("Parsed: %ld\n", n);
}
/* String search */
char haystack[] = "Hello, World!";
char *found = strstr(haystack, "World");
if (found) printf("Found at index %td\n", found - haystack);
/* Convert to uppercase in-place */
for (char *p = haystack; *p; p++) *p = toupper((unsigned char)*p);
printf("%s\n", haystack);
return 0;
}Cfile_io.c
File I/O: fopen, fgets, fprintf, fclose
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* Write CSV file */
void write_csv(const char *path) {
FILE *f = fopen(path, "w");
if (!f) { perror("fopen"); return; }
fprintf(f, "name,age,score\n");
fprintf(f, "Alice,30,95.5\n");
fprintf(f, "Bob,25,87.0\n");
fclose(f); /* always close — flushes buffer */
}
/* Read CSV line by line */
void read_csv(const char *path) {
FILE *f = fopen(path, "r");
if (!f) { perror("fopen"); return; }
char line[256];
int lineno = 0;
while (fgets(line, sizeof(line), f)) {
/* fgets includes '\n' — strip it */
size_t len = strlen(line);
if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';
if (lineno++ == 0) { continue; } /* skip header */
printf("Line: %s\n", line);
}
if (ferror(f)) perror("read error");
fclose(f);
}
/* Binary I/O */
void write_binary(const char *path, const int *data, size_t count) {
FILE *f = fopen(path, "wb");
if (!f) return;
fwrite(data, sizeof(int), count, f);
fclose(f);
}
int main(void) {
write_csv("/tmp/test.csv");
read_csv("/tmp/test.csv");
return 0;
}Clinked_list.c
Singly linked list: push, pop, print, free
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next; /* must use struct Node here — typedef not yet complete */
} Node;
Node *node_new(int value) {
Node *n = malloc(sizeof(Node));
if (!n) return NULL;
n->value = value;
n->next = NULL;
return n;
}
/* Prepend: O(1) */
Node *list_prepend(Node *head, int value) {
Node *n = node_new(value);
if (!n) return head;
n->next = head;
return n; /* new head */
}
void list_print(const Node *head) {
for (const Node *n = head; n; n = n->next)
printf("%d -> ", n->value);
printf("NULL\n");
}
int list_length(const Node *head) {
int count = 0;
for (const Node *n = head; n; n = n->next) count++;
return count;
}
/* Free entire list */
void list_free(Node *head) {
while (head) {
Node *next = head->next; /* save next BEFORE freeing */
free(head);
head = next;
}
}
int main(void) {
Node *head = NULL;
head = list_prepend(head, 3);
head = list_prepend(head, 2);
head = list_prepend(head, 1);
list_print(head); /* 1 -> 2 -> 3 -> NULL */
printf("Length: %d\n", list_length(head));
list_free(head);
return 0;
}Cfunction_pointers.c
Function pointers: callbacks and dispatch tables
#include <stdio.h>
#include <stdlib.h>
/* Function pointer typedef: cleaner than inline syntax */
typedef int (*Comparator)(const void *, const void *);
typedef void (*Processor)(int);
int compare_asc(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
int compare_desc(const void *a, const void *b) {
return *(int*)b - *(int*)a;
}
void print_item(int x) { printf("%d ", x); }
void double_item(int x) { printf("%d ", x * 2); }
void apply_to_array(const int *arr, int n, Processor fn) {
for (int i = 0; i < n; i++) fn(arr[i]);
printf("\n");
}
/* Dispatch table: array of function pointers */
typedef struct {
const char *name;
void (*handler)(const char *);
} Command;
void cmd_hello(const char *arg) { printf("Hello, %s!\n", arg); }
void cmd_quit (const char *arg) { (void)arg; printf("Goodbye.\n"); }
int main(void) {
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare_asc);
apply_to_array(arr, n, print_item); /* 1 2 5 8 9 */
qsort(arr, n, sizeof(int), compare_desc);
apply_to_array(arr, n, double_item); /* 18 16 10 4 2 */
/* Dispatch table */
Command commands[] = {
{"hello", cmd_hello},
{"quit", cmd_quit},
};
/* Look up and call */
commands[0].handler("World"); /* Hello, World! */
return 0;
}Carrays_2d.c
Arrays: 2D, dynamic, and sizeof idiom
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 3
#define COLS 4
int main(void) {
/* Static 2D array: row-major storage */
int matrix[ROWS][COLS] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) printf("%3d", matrix[r][c]);
printf("\n");
}
/* sizeof idiom: count elements (only in declaring scope) */
int arr[] = {10, 20, 30, 40, 50};
int n = (int)(sizeof(arr) / sizeof(arr[0])); /* 5 */
printf("count: %d\n", n);
/* Dynamic 2D array: array of pointers */
int rows = 4, cols = 5;
int **dyn = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
dyn[i] = calloc(cols, sizeof(int));
}
dyn[2][3] = 42;
printf("dyn[2][3] = %d\n", dyn[2][3]);
/* Free: inner arrays first, then outer */
for (int i = 0; i < rows; i++) free(dyn[i]);
free(dyn);
/* Flat dynamic 2D (more cache-friendly) */
int *flat = malloc(rows * cols * sizeof(int));
flat[2 * cols + 3] = 99; /* row 2, col 3 */
printf("flat[2][3] = %d\n", flat[2 * cols + 3]);
free(flat);
return 0;
}Cbit_manipulation.c
Bit manipulation: set, clear, toggle, check
#include <stdio.h>
#include <stdint.h>
/* Bit flags using an enum */
typedef enum {
FLAG_READ = 1 << 0, /* 0001 = 1 */
FLAG_WRITE = 1 << 1, /* 0010 = 2 */
FLAG_EXECUTE = 1 << 2, /* 0100 = 4 */
FLAG_HIDDEN = 1 << 3, /* 1000 = 8 */
} FileFlags;
void print_flags(uint8_t flags) {
printf("r:%d w:%d x:%d h:%d\n",
(flags & FLAG_READ) ? 1 : 0,
(flags & FLAG_WRITE) ? 1 : 0,
(flags & FLAG_EXECUTE) ? 1 : 0,
(flags & FLAG_HIDDEN) ? 1 : 0);
}
int main(void) {
uint8_t flags = 0;
/* Set bits */
flags |= FLAG_READ;
flags |= FLAG_WRITE;
print_flags(flags); /* r:1 w:1 x:0 h:0 */
/* Clear a bit */
flags &= ~FLAG_WRITE;
print_flags(flags); /* r:1 w:0 x:0 h:0 */
/* Toggle a bit */
flags ^= FLAG_EXECUTE;
print_flags(flags); /* r:1 w:0 x:1 h:0 */
/* Check if bit is set */
if (flags & FLAG_READ) printf("readable\n");
/* Common tricks */
int n = 42;
printf("is even: %s\n", (n & 1) ? "no" : "yes");
printf("multiply by 2: %d\n", n << 1); /* left shift */
printf("divide by 2: %d\n", n >> 1); /* right shift (arithmetic for signed) */
printf("clear lowest: %d\n", n & (n-1)); /* clears lowest set bit */
printf("isolate lowest: %d\n", n & (-n)); /* isolates lowest set bit */
return 0;
}Cerror_handling.c
Error handling: errno, perror, return codes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* C error handling: return codes + errno */
int read_config(const char *path, char *buf, size_t bufsize) {
FILE *f = fopen(path, "r");
if (!f) {
/* errno set by fopen */
fprintf(stderr, "fopen(%s): %s\n", path, strerror(errno));
return -1;
}
size_t bytes = fread(buf, 1, bufsize - 1, f);
if (ferror(f)) {
perror("fread"); /* perror: prints errno message to stderr */
fclose(f);
return -2;
}
buf[bytes] = '\0';
fclose(f);
return 0; /* success */
}
/* Cleanup goto: common C pattern for resource management */
int process_data(const char *in_path, const char *out_path) {
int ret = 0;
FILE *in = NULL, *out = NULL;
in = fopen(in_path, "r");
if (!in) { perror("open input"); ret = -1; goto cleanup; }
out = fopen(out_path, "w");
if (!out) { perror("open output"); ret = -2; goto cleanup; }
/* ... process files ... */
cleanup:
if (in) fclose(in); /* safe — fclose(NULL) is OK but avoid it */
if (out) fclose(out);
return ret;
}
int main(void) {
char buf[1024];
int result = read_config("/etc/hostname", buf, sizeof(buf));
if (result == 0) {
printf("hostname: %s\n", buf);
} else {
fprintf(stderr, "Failed with code %d\n", result);
}
return 0;
}Cgeneric_sort.c
qsort with comparators and bsearch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Comparator for qsort: return neg/0/pos */
int cmp_int_asc(const void *a, const void *b) {
int x = *(int*)a, y = *(int*)b;
return (x > y) - (x < y); /* safe — avoids overflow from subtraction */
}
int cmp_str(const void *a, const void *b) {
return strcmp(*(const char**)a, *(const char**)b);
}
typedef struct { char name[32]; int age; } Person;
int cmp_person_age(const void *a, const void *b) {
return ((Person*)a)->age - ((Person*)b)->age;
}
int main(void) {
/* Sort integers */
int nums[] = {5, 2, 8, 1, 9, 3};
int n = sizeof(nums) / sizeof(nums[0]);
qsort(nums, n, sizeof(int), cmp_int_asc);
for (int i = 0; i < n; i++) printf("%d ", nums[i]); /* 1 2 3 5 8 9 */
printf("\n");
/* Binary search (requires sorted array) */
int key = 5;
int *found = bsearch(&key, nums, n, sizeof(int), cmp_int_asc);
if (found) printf("Found %d at index %td\n", *found, found - nums);
/* Sort strings */
const char *words[] = {"banana", "apple", "cherry", "date"};
int wn = sizeof(words) / sizeof(words[0]);
qsort(words, wn, sizeof(char*), cmp_str);
for (int i = 0; i < wn; i++) printf("%s ", words[i]); /* apple banana cherry date */
printf("\n");
/* Sort structs */
Person people[] = {{"Alice",30},{"Bob",25},{"Carol",35}};
qsort(people, 3, sizeof(Person), cmp_person_age);
for (int i = 0; i < 3; i++) printf("%s(%d) ", people[i].name, people[i].age);
printf("\n"); /* Bob(25) Alice(30) Carol(35) */
return 0;
}Cpreprocessor.c
Preprocessor: safe macros, X-macros, static_assert
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
/* Safe macros: parenthesise everything */
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0])) /* only safe in declaring scope */
#define UNUSED(x) (void)(x) /* suppress unused variable warning */
/* Stringify and token paste */
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define LINE_STR TOSTRING(__LINE__)
/* X-macro: define data once, use in multiple contexts */
#define COLORS(X) \
X(RED, 0xFF0000) \
X(GREEN, 0x00FF00) \
X(BLUE, 0x0000FF)
typedef enum {
#define X(name, value) name,
COLORS(X)
#undef X
COLOR_COUNT
} Color;
const char *color_names[] = {
#define X(name, value) STRINGIFY(name),
COLORS(X)
#undef X
};
/* static_assert: compile-time check */
static_assert(sizeof(int) == 4, "Expected 32-bit int");
static_assert(ARRAY_LEN(color_names) == COLOR_COUNT, "Color table mismatch");
int main(void) {
printf("MAX(3,7) = %d\n", MAX(3, 7)); /* 7 */
printf("ABS(-5) = %d\n", ABS(-5)); /* 5 */
printf("Colors: %d\n", COLOR_COUNT); /* 3 */
printf("Color 0: %s\n", color_names[RED]); /* RED */
return 0;
}C reference — C overview · Learn C
Everything C in one place — learning paths, reference, playground, and more.
C Hub →