Pointers in C Programming (Memory Architecture Guide)

Pointers in C — conceptual cover illustration
Pointers in C — conceptual cover illustration

Pointers give C its unmatched performance and systems-level control. At its core, a pointer is simply a variable that stores the physical or virtual memory address of another variable. By mastering pointers, you unlock dynamic memory allocation, efficient pass-by-reference semantics, high-performance data structures, and hardware-level memory access.

1. Memory Addresses (&) and the Dereference Operator (*)

Every variable in a C program resides at a unique memory address in RAM. The address-of operator (&) extracts this physical location. Conversely, the dereference operator (*) instructs the CPU to navigate to that memory address and read or mutate the value stored inside.

int score = 95;
int *ptr = &score; // ptr stores the memory address of score

printf("Address of score : %p\n", (void *)ptr);
printf("Value via ptr    : %d\n", *ptr);

*ptr = 100; // Mutates score directly in memory
printf("Updated score    : %d\n", score); // Prints 100

2. Pointer Arithmetic and Byte Stride Math

Unlike standard integer arithmetic, adding 1 to a pointer (ptr + 1) does NOT increment the memory address by 1 byte. Instead, it advances the pointer address by sizeof(*ptr) bytes. If ptr points to a 4-byte integer at address 0x1000, ptr + 1 advances to 0x1004. This stride arithmetic enables fast traversal across contiguous array elements.

3. Double Pointers (Pointers to Pointers)

A double pointer (e.g., int **pptr) stores the address of another pointer variable. Double pointers are essential when you need a function to modify where a caller pointer points—such as allocating heap memory inside a helper function or modifying head pointers in linked lists.

void allocate_buffer(int **buf_ptr, int size) {
    *buf_ptr = (int *)malloc(size * sizeof(int));
}

int main(void) {
    int *my_buffer = NULL;
    allocate_buffer(&my_buffer, 10);
    // my_buffer now holds valid heap memory
    free(my_buffer);
    return 0;
}

4. Void Pointers, NULL Safety & Dangling Pointer Defense

A void* is a generic pointer that can hold the address of any data type without casting (used by malloc() and qsort()). However, because void has an unknown size, you cannot dereference or perform pointer arithmetic on a void* without casting it first. Always verify pointers against NULL before dereferencing to prevent fatal segmentation faults.

Runnable C example

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

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int main(void) {
    int score = 95;
    int *ptr = &score;

    printf("Value via ptr : %d\n", *ptr);
    *ptr = 100;
    printf("Updated score : %d\n", score);

    int nums[4] = {10, 20, 30, 40};
    int *p = nums;
    for (int i = 0; i < 4; i++) {
        printf("*(p + %d) = %d\n", i, *(p + i));
    }
    printf("Bytes between p and p + 1: %zu\n",
           (size_t)((char *)(p + 1) - (char *)p));

    int x = 1, y = 2;
    swap(&x, &y);
    printf("After swap: x = %d, y = %d\n", x, y);

    int *heap = malloc(3 * sizeof(int));
    if (heap == NULL) {
        return 1;
    }
    for (int i = 0; i < 3; i++) {
        heap[i] = (i + 1) * 5;
    }
    printf("Heap values: %d %d %d\n", heap[0], heap[1], heap[2]);
    free(heap);
    heap = NULL;
    printf("heap is %s after free\n", heap == NULL ? "NULL" : "not NULL");
    return 0;
}

Open example in compiler

Expected Output

Value via ptr : 95
Updated score : 100
*(p + 0) = 10
*(p + 1) = 20
*(p + 2) = 30
*(p + 3) = 40
Bytes between p and p + 1: 4
After swap: x = 2, y = 1
Heap values: 5 10 15
heap is NULL after free

Frequently Asked Questions

What is a NULL pointer and why is it important?

A NULL pointer is assigned to address 0 (or (void*)0), explicitly indicating that it points to no valid memory location. Modern operating systems intentionally leave virtual page 0 unmapped so that accidental dereferences fail immediately with SIGSEGV rather than corrupting memory.

What is the size of a pointer variable in C?

A pointer size depends entirely on CPU architecture, not the data type it points to. On a 32-bit system, all pointers are 4 bytes. On a 64-bit system, all pointers are 8 bytes.

Related learn