Memory & malloc/free

Every local variable you've declared so far lives on the stack, and disappears automatically when the function it's in returns. The heap is a separate pool of memory you manage by hand — you ask for it with malloc, and it stays reserved until you explicitly give it back with free.

Stack vs. heap

The stack is fast and automatic, but fixed in size and tied to a function's lifetime — you can't return a pointer to a local array and expect it to still be valid. The heap is slower and manual, but it lasts as long as you want it to, and its size can be decided while the program is running:

C main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *nums = malloc(5 * sizeof(int));

    if (nums == NULL) {
        printf("Allocation failed\n");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        nums[i] = i * i;
    }
    for (int i = 0; i < 5; i++) {
        printf("%d ", nums[i]);
    }
    printf("\n");

    free(nums);
    return 0;
}
Output
0 1 4 9 16 

malloc(5 * sizeof(int)) asks the heap for enough room for 5 integers and hands back a pointer to the start of it — or NULL if the request couldn't be satisfied, which is why checking for NULL before using the pointer isn't optional. Unlike a stack array, nums here has a size that was computed at runtime, and it would still be valid even if this allocation happened inside a function that later returned.

Note: memory from malloc is not automatically cleaned up. Every successful malloc needs exactly one matching free once you're done with it — forget it, and that memory stays reserved for the rest of the program's run, a memory leak. In a short-lived program that might not matter; in a long-running server it will eventually exhaust available memory.

free, and the mistakes around it

free gives memory back, but it comes with two sharp edges: using a pointer after it's been freed (use-after-free), and freeing the same pointer twice (double-free). Both are undefined behavior — sometimes they crash immediately, sometimes they silently corrupt memory that gets used much later:

C main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *value = malloc(sizeof(int));
    *value = 99;

    printf("%d\n", *value);
    free(value);
    value = NULL;  // safe: reading/freeing NULL again won't corrupt memory

    return 0;
}
Output
99

Setting value = NULL immediately after free(value) is a common defensive habit: it doesn't undo the free, but it turns any accidental later use of value into an obvious, catchable NULL dereference instead of silent corruption of memory that's since been handed out to something else.

Course complete: that covers the C course from top to bottom — compiling and running a program, variables and data types, operators, printf and scanf, conditionals, loops, functions, arrays, strings, pointers, structs, and manual memory management with malloc and free. Between pointers, arrays, and manual memory, you now have the pieces that every higher-level language's runtime is quietly built out of underneath you.