Back to blog
Backend Systemsbeginner

C Pointers & Memory Management

Understand C pointers: declaration, dereferencing, pointer arithmetic, and dynamic memory with malloc/free. The most important topic in C.

Asma HafeezApril 17, 20265 min read
cpointersmemorymallocheap
Share:𝕏

C Pointers & Memory Management

Pointers are what make C powerful — and what makes it dangerous. Understanding them deeply is the difference between writing correct C and producing crashes.


What is a Pointer?

A pointer is a variable that stores a memory address.

C
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);    // 0x7fff... (some address)
printf("Value of ptr:     %p\n",  ptr);   // same address as &x
printf("Dereferenced ptr: %d\n", *ptr);   // 42 — read the value at ptr

// Modify through pointer
*ptr = 100;
printf("x is now: %d\n", x);  // 100

Passing by Pointer (Modify Arguments)

C
// Pass by value — can't modify original
void double_value_wrong(int n) {
    n *= 2;  // only changes the local copy
}

// Pass by pointer — CAN modify original
void double_value(int* n) {
    *n *= 2;  // modifies what n points to
}

int x = 5;
double_value(&x);     // pass address of x
printf("%d\n", x);    // 10

Returning multiple values

C
// min and max in one call
void min_max(const int* arr, int n, int* out_min, int* out_max) {
    if (n == 0) return;
    *out_min = arr[0];
    *out_max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] < *out_min) *out_min = arr[i];
        if (arr[i] > *out_max) *out_max = arr[i];
    }
}

int nums[] = {3, 1, 4, 1, 5, 9, 2};
int mn, mx;
min_max(nums, 7, &mn, &mx);
printf("Min: %d, Max: %d\n", mn, mx);  // Min: 1, Max: 9

Pointers and Arrays

Arrays and pointers are closely related in C.

C
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr;  // ptr points to arr[0] (no & needed for arrays)

// Equivalent ways to access elements
printf("%d\n", arr[2]);    // 30
printf("%d\n", *(ptr+2));  // 30 — pointer arithmetic
printf("%d\n", ptr[2]);    // 30 — pointer used like array

// Pointer arithmetic
ptr++;          // ptr now points to arr[1]
printf("%d\n", *ptr);  // 20

Passing arrays to functions

C
// These two declarations are equivalent:
void print_array(int* arr, int n);
void print_array(int arr[], int n);

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

Stack vs Heap

| | Stack | Heap | |---|---|---| | Allocation | Automatic | Manual (malloc/free) | | Size | Limited (~1-8 MB) | Large (limited by RAM) | | Lifetime | Until function returns | Until free() is called | | Speed | Fast | Slower |

C
void stack_example(void) {
    int x = 10;          // stack — freed when function returns
    int arr[100];        // stack — 400 bytes on stack
    // Do NOT return a pointer to a local variable!
}

// Heap allocation
int* heap_example(int n) {
    int* arr = malloc(n * sizeof(int));   // allocate on heap
    if (arr == NULL) {
        fprintf(stderr, "malloc failed\n");
        return NULL;
    }
    // ... use arr ...
    return arr;  // caller must free this!
}

Dynamic Memory — malloc, calloc, realloc, free

C
#include <stdlib.h>

// malloc — allocate uninitialized memory
int* arr = malloc(10 * sizeof(int));
if (arr == NULL) { /* handle error */ }

// calloc — allocate zero-initialized memory
int* zeros = calloc(10, sizeof(int));  // all elements are 0

// realloc — resize existing allocation
arr = realloc(arr, 20 * sizeof(int));
if (arr == NULL) { /* original arr may be leaked! use temp ptr */ }

// free — release memory
free(arr);
arr = NULL;  // set to NULL after free — prevents use-after-free

Dynamic array pattern

C
typedef struct {
    int*  data;
    int   size;
    int   capacity;
} IntArray;

IntArray* create_array(int initial_capacity) {
    IntArray* arr = malloc(sizeof(IntArray));
    if (!arr) return NULL;
    arr->data = malloc(initial_capacity * sizeof(int));
    if (!arr->data) { free(arr); return NULL; }
    arr->size = 0;
    arr->capacity = initial_capacity;
    return arr;
}

int push(IntArray* arr, int value) {
    if (arr->size >= arr->capacity) {
        int new_cap = arr->capacity * 2;
        int* new_data = realloc(arr->data, new_cap * sizeof(int));
        if (!new_data) return -1;  // allocation failed
        arr->data = new_data;
        arr->capacity = new_cap;
    }
    arr->data[arr->size++] = value;
    return 0;  // success
}

void free_array(IntArray* arr) {
    if (arr) {
        free(arr->data);
        free(arr);
    }
}

Pointers to Structs

C
typedef struct {
    char name[50];
    int  age;
} Person;

Person* create_person(const char* name, int age) {
    Person* p = malloc(sizeof(Person));
    if (!p) return NULL;
    strncpy(p->name, name, sizeof(p->name) - 1);
    p->name[sizeof(p->name) - 1] = '\0';
    p->age = age;
    return p;
}

Person* alice = create_person("Alice", 30);

// Two ways to access struct members through a pointer
printf("%s\n", (*alice).name);  // dereference then access
printf("%s\n", alice->name);    // arrow operator — equivalent, cleaner

free(alice);
alice = NULL;

Common Pointer Bugs

C
// 1. NULL pointer dereference
int* p = NULL;
// *p = 5;  // CRASH — segmentation fault

// 2. Dangling pointer
int* p2 = malloc(sizeof(int));
free(p2);
// *p2 = 5;  // undefined behavior — memory was freed

// 3. Memory leak
int* p3 = malloc(100 * sizeof(int));
// function returns without free(p3) — leak!

// 4. Double free
int* p4 = malloc(sizeof(int));
free(p4);
// free(p4);  // undefined behavior

// 5. Buffer overflow
int arr[5];
// arr[10] = 99;  // writes past array — corrupts memory

Key Takeaways

  1. A pointer stores an address — dereference with * to get the value
  2. Use & to get the address of a variable, * to dereference a pointer
  3. The -> operator is shorthand for (*ptr).member
  4. Always check malloc return value — it returns NULL on failure
  5. Every malloc needs exactly one free — set pointer to NULL after freeing

Enjoyed this article?

Explore the Backend Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.