Skip to content
C Programming Language Guide — Pointers, Memory, and Systems Programming

C Programming Language Guide — Pointers, Memory, and Systems Programming

DodaTech Updated Jun 7, 2026 7 min read

C is a procedural systems programming language that gives you direct control over memory through pointers and manual allocation, forming the foundation of operating systems, embedded firmware, and high-performance computing.

What You’ll Learn

  • Pointers and pointer arithmetic
  • Manual memory management with malloc and free
  • Structs for custom data types
  • File I/O operations
  • Building projects with Make and gcc

Why It Matters

C is the language that built everything — Linux, Windows, Python, Git, and virtually every operating system kernel. Durga Antivirus Pro uses C in its core scanning engine for maximum performance and low-level file system access. Understanding C gives you insight into how computers actually work, making you a better programmer in every other language. Embedded systems, IoT devices, and game engines all rely on C.

Learning Path

    flowchart LR
  A[C Basics<br/>You are here] --> B[Pointers & Arrays]
  B --> C[Memory Management]
  C --> D[Structs & File I/O]
  D --> E[Build an Embedded App]
  

Your First C Program

C programs start at the main function. The #include directive brings in header files with function declarations.

#include <stdio.h>

int main() {
    printf("Hello, C!\n");
    return 0;
}
gcc hello.c -o hello
./hello
# Hello, C!

Pointers

A pointer stores a memory address. The * operator dereferences it; & gets an address.

#include <stdio.h>

int main() {
    int x = 42;
    int *ptr = &x;  // ptr holds the address of x

    printf("Value of x: %d\n", x);       // 42
    printf("Address of x: %p\n", &x);     // 0x7ff...
    printf("Value at ptr: %d\n", *ptr);   // 42

    *ptr = 100;  // change x through the pointer
    printf("New x: %d\n", x);             // 100

    return 0;
}

Pointer Arithmetic

Adding to a pointer moves it by multiples of the type’s size.

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // points to arr[0]

    printf("%d ", *ptr);        // 10
    printf("%d ", *(ptr + 1));  // 20
    printf("%d ", *(ptr + 2));  // 30
    printf("%d ", *(ptr + 3));  // 40
    printf("%d\n", *(ptr + 4)); // 50

    // Equivalent array notation:
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(arr + i));
    }
    printf("\n");
    // 10 20 30 40 50

    return 0;
}

Memory Management with malloc and free

C requires manual memory allocation. malloc allocates memory on the heap; free releases it.

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

int main() {
    int *arr;
    int n = 5;

    // Allocate memory for 5 integers
    arr = (int *)malloc(n * sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // Use the memory
    for (int i = 0; i < n; i++) {
        arr[i] = i * i;
    }

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    // 0 1 4 9 16

    // Free the memory
    free(arr);
    arr = NULL;  // prevent dangling pointer

    return 0;
}

Structs

Structs group related variables together.

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

struct Student {
    char name[50];
    int age;
    float gpa;
};

int main() {
    struct Student s1;

    strcpy(s1.name, "Alice");
    s1.age = 20;
    s1.gpa = 3.8;

    printf("Name: %s\n", s1.name);   // Name: Alice
    printf("Age: %d\n", s1.age);     // Age: 20
    printf("GPA: %.1f\n", s1.gpa);   // GPA: 3.8

    return 0;
}

File I/O

C reads and writes files through file pointers.

#include <stdio.h>

int main() {
    // Write to a file
    FILE *f = fopen("data.txt", "w");
    if (f == NULL) {
        printf("Error opening file\n");
        return 1;
    }
    fprintf(f, "Line 1: Hello\n");
    fprintf(f, "Line 2: World\n");
    fclose(f);

    // Read from a file
    f = fopen("data.txt", "r");
    char buffer[100];
    while (fgets(buffer, sizeof(buffer), f) != NULL) {
        printf("%s", buffer);
    }
    fclose(f);

    return 0;
}

Output:

Line 1: Hello
Line 2: World

Make and GCC

A Makefile automates compilation. Here’s a minimal example:

CC = gcc
CFLAGS = -Wall -Wextra -std=c99

all: program

program: main.c utils.c
	$(CC) $(CFLAGS) -o program main.c utils.c

clean:
	rm -f program
make
# gcc -Wall -Wextra -std=c99 -o program main.c utils.c

Common Mistakes

1. Off-by-one errors in arrays

int arr[5];
arr[5] = 10;  // buffer overflow — accessing memory beyond the array

Array indexes go from 0 to n-1. Accessing arr[n] is undefined behavior.

2. Forgetting to free memory (memory leaks)

Every malloc must have a matching free. Long-running programs that leak memory will eventually exhaust available RAM.

3. Using uninitialized pointers

int *ptr;
*ptr = 5;  // crash — ptr points to garbage

Always initialize pointers to NULL or a valid address.

4. Dangling pointers after free

int *ptr = malloc(sizeof(int));
free(ptr);
*ptr = 5;  // use-after-free — undefined behavior

Set ptr = NULL after freeing.

5. Confusing = with == in conditions

if (x = 5)  // assignment, always true!
if (x == 5) // comparison, correct

6. Buffer overflow with string functions

gets() is unsafe and was removed from C11. Always use fgets() with a size limit.

Practice Questions

  1. What does sizeof(int) return? Usually 4 bytes, but it’s platform-dependent. Always use sizeof instead of hardcoding sizes.

  2. What is the difference between malloc and calloc? malloc allocates uninitialized memory. calloc allocates and zero-initializes. Both return void *.

  3. How do you prevent buffer overflow in C? Use bounded functions like fgets, strncpy, snprintf instead of their unbounded counterparts.

  4. What does * do in a pointer declaration vs. dereference? In int *p, * declares a pointer. In *p = 5, * dereferences it. Same symbol, different meaning by context.

  5. What is a segmentation fault? Accessing memory your program doesn’t own — reading past an array, dereferencing NULL, or writing to read-only memory.

Challenge: Write a C program that reads integers from a file into a dynamically allocated array, sorts them with qsort, and writes the sorted result to a new file.

Mini Project — File Size Analyzer

Build a tool that scans a directory, reports each file’s size in human-readable format, and calculates total disk usage.

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>

void print_size(long bytes) {
    if (bytes < 1024)
        printf("%ld B", bytes);
    else if (bytes < 1024 * 1024)
        printf("%.1f KB", bytes / 1024.0);
    else
        printf("%.1f MB", bytes / (1024.0 * 1024.0));
}

int main(int argc, char *argv[]) {
    const char *path = (argc > 1) ? argv[1] : ".";
    DIR *dir = opendir(path);

    if (dir == NULL) {
        printf("Cannot open directory: %s\n", path);
        return 1;
    }

    struct dirent *entry;
    long total = 0;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] == '.') continue;  // skip hidden files

        struct stat st;
        char fullpath[1024];
        snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);

        if (stat(fullpath, &st) == 0) {
            printf("%-30s ", entry->d_name);
            print_size(st.st_size);
            printf("\n");
            total += st.st_size;
        }
    }

    printf("------------------------\n");
    printf("%-30s ", "Total");
    print_size(total);
    printf("\n");

    closedir(dir);
    return 0;
}

FAQ

Why is C still used?
C provides unmatched control over hardware with minimal runtime overhead. Operating systems, embedded systems, and firmware are written in C because no higher-level language can match its performance and predictability.
How is C different from C++?
C is procedural; C++ adds object-oriented features, templates, exceptions, and a richer standard library. C can be compiled with a C++ compiler, but not vice versa.
What is undefined behavior in C?
When the C standard doesn’t define what happens — reading past an array, signed integer overflow, dereferencing NULL. The program might crash, produce wrong results, or appear to work until it doesn’t.
Is C good for beginners?
C teaches how computers actually work — memory, pointers, data representation. It’s harder than Python but provides foundational knowledge that transfers to every other language.
What is the difference between stack and heap?
Stack: automatic, fast, limited size (∼8MB). Heap: manual allocation with malloc, slower, limited by available RAM. Local variables go on the stack; dynamically sized data goes on the heap.
What is a Makefile?
A build automation file that defines compilation rules. make reads the Makefile and runs only the commands needed based on file timestamps.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro