Coding 101

C Programming Basics: 8 Fundamental Programs Every Programmer Must Write

DD
Ankur Ishwar
12 min read Updated Sep 7, 2026
c basic programs

When you start learning to code with Python or JavaScript, you can write thousands of lines of code without ever understanding how RAM, CPU registers, or cache lines function. The language hides memory pointers, garbage collection, and system calls behind convenient abstractions.

C provides no such cushions. In C, you face the bare hardware directly. If you forget to allocate memory, you get a segmentation fault. If you read past an array boundary, you corrupt stack variables. That discipline makes you a ten times better engineer, whether you eventually write Go, Rust, TypeScript, or Java.

During my early programming days, working through basic C exercises on a slow secondhand laptop taught me more about operating systems than any textbook. Here are eight foundational C programs every serious developer should implement by hand, with compilable code and explanations of common runtime traps.

1. Safe User Input and Buffer Parsing

Beginner tutorials frequently teach scanf("%d", &val). That is dangerous in real software: if a user enters a character like 'x' instead of a number, scanf fails silently, leaves the character in standard input, and creates an infinite loop if wrapped in a while statement.

The correct, industrial approach uses fgets followed by sscanf or strtol:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int read_integer(const char *prompt, int *result) {
    char buffer[64];
    printf("%s", prompt);

    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
        return 0; // EOF or read failure
    }

    char *endptr;
    errno = 0;
    long val = strtol(buffer, &endptr, 10);

    // Check for conversion error or no digits entered
    if (endptr == buffer || errno != 0) {
        return 0;
    }

    *result = (int)val;
    return 1;
}

int main(void) {
    int age;
    if (read_integer("Enter your age: ", &age)) {
        printf("Recorded age: %d\n", age);
    } else {
        printf("Invalid numerical input.\n");
    }
    return 0;
}

2. Palindrome Verification Using Pointers

Checking if a string reads the same forwards and backwards tests pointer navigation without extra array allocation.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int is_palindrome(const char *str) {
    if (str == NULL) return 0;

    const char *left = str;
    const char *right = str + strlen(str) - 1;

    while (left < right) {
        while (left < right && !isalnum((unsigned char)*left)) left++;
        while (left < right && !isalnum((unsigned char)*right)) right--;

        if (tolower((unsigned char)*left) != tolower((unsigned char)*right)) {
            return 0;
        }
        left++;
        right--;
    }
    return 1;
}

int main(void) {
    const char *sample = "A man, a plan, a canal: Panama";
    printf("Is '%s' a palindrome? %s\n", sample, is_palindrome(sample) ? "Yes" : "No");
    return 0;
}

3. Prime Number Sieve of Eratosthenes

Trial division up to sqrt(N) works for small numbers, but finding all primes up to 1,000,000 requires the Sieve of Eratosthenes with O(N log log N) complexity:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

void find_primes_up_to(int limit) {
    bool *is_prime = (bool *)malloc((limit + 1) * sizeof(bool));
    if (!is_prime) {
        perror("Memory allocation error");
        return;
    }

    for (int i = 0; i <= limit; i++) is_prime[i] = true;
    is_prime[0] = is_prime[1] = false;

    for (int p = 2; p * p <= limit; p++) {
        if (is_prime[p]) {
            for (int i = p * p; i <= limit; i += p) {
                is_prime[i] = false;
            }
        }
    }

    int prime_count = 0;
    for (int p = 2; p <= limit; p++) {
        if (is_prime[p]) prime_count++;
    }

    printf("Total primes up to %d: %d\n", limit, prime_count);
    free(is_prime);
}

int main(void) {
    find_primes_up_to(100000);
    return 0;
}

4. Matrix Multiplication with Row-Major Cache Awareness

In C, multi-dimensional arrays reside in memory in row-major order. Accessing elements sequentially along rows utilizes CPU L1 and L2 cache lines. Jumping down columns produces cache misses, slowing down execution by five to ten times on large datasets:

#include <stdio.h>

#define SIZE 3

void multiply_matrices(const int a[SIZE][SIZE], const int b[SIZE][SIZE], int result[SIZE][SIZE]) {
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            result[i][j] = 0;
        }
    }

    // Loop order i-k-j maximizes cache hits for matrix b
    for (int i = 0; i < SIZE; i++) {
        for (int k = 0; k < SIZE; k++) {
            int r = a[i][k];
            for (int j = 0; j < SIZE; j++) {
                result[i][j] += r * b[k][j];
            }
        }
    }
}

int main(void) {
    int m1[SIZE][SIZE] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    int m2[SIZE][SIZE] = {{9, 8, 7}, {6, 5, 4}, {3, 2, 1}};
    int out[SIZE][SIZE];

    multiply_matrices(m1, m2, out);
    printf("Result top-left cell: %d\n", out[0][0]); // 1*9 + 2*6 + 3*3 = 30
    return 0;
}

5. Binary Search with Overflow Prevention

A classic bug that survived in the JDK for nearly a decade was calculating midpoints with int mid = (low + high) / 2. When low + high exceeds 2,147,483,647, it overflows into negative numbers. Always calculate the midpoint with offset subtraction:

#include <stdio.h>

int binary_search(const int arr[], int size, int target) {
    int low = 0;
    int high = size - 1;

    while (low <= high) {
        // Safe from 32-bit signed overflow
        int mid = low + (high - low) / 2;

        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return -1; // Target not found
}

int main(void) {
    int numbers[] = {3, 9, 14, 22, 45, 67, 89, 99};
    int index = binary_search(numbers, 8, 45);
    printf("Index of 45: %d\n", index);
    return 0;
}

6. Line-by-Line Safe File Processing

Writing resilient file processing in C requires checking return pointers on open and closing file handles cleanly to avoid operating system file descriptor leaks:

#include <stdio.h>

int count_lines_in_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Could not open file");
        return -1;
    }

    int line_count = 0;
    char buffer[256];

    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        line_count++;
    }

    fclose(fp);
    return line_count;
}

7. Dynamic Memory Reversal for Variable-Sized Arrays

Allocating heap memory dynamically with malloc and validating allocation boundaries before use:

#include <stdio.h>
#include <stdlib.h>

void reverse_array(int *arr, size_t len) {
    if (arr == NULL || len < 2) return;
    int *left = arr;
    int *right = arr + len - 1;

    while (left < right) {
        int tmp = *left;
        *left = *right;
        *right = tmp;
        left++;
        right--;
    }
}

8. Fibonacci Generator Preventing 64-Bit Integer Overflow

Fibonacci grows exponentially. A 32-bit signed integer overflows at the 47th number. A 64-bit unsigned integer (uint64_t) reaches overflow at the 94th term. Always validate arithmetic thresholds:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

void print_fibonacci(int count) {
    if (count > 93) count = 93; // Cap to uint64_t limit

    uint64_t a = 0, b = 1;
    for (int i = 0; i < count; i++) {
        printf("F(%d) = %" PRIu64 "\n", i, a);
        uint64_t next = a + b;
        a = b;
        b = next;
    }
}

int main(void) {
    print_fibonacci(10);
    return 0;
}

Where to Go from Here

Once you are comfortable with these basic programs, advance to pointer-heavy data structures and interview questions in our guide on essential C programming interview programs. To understand how C shaped modern computing, explore the history and importance of the C language.

If you are also exploring full-stack engineering, review our foundational guide on the basics of web development for beginners.

Found this useful?
View all articles

Keep Reading

Related Articles

Learn with Dropout Developer

Build real software with AI

Step-by-step learning paths, vibe coding tutorials, and certified developer programs designed for the modern engineer.