Skip to content

C Pointer Arithmetic — Increment, Decrement, Array Traversal, and Pointer Difference

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn about C Pointer Arithmetic. We cover key concepts, practical examples, and best practices to help you master this topic.

C pointer arithmetic allows you to move a pointer through memory by adding or subtracting integer values, with the step size automatically adjusted based on the pointer's type size.

Why It Matters

Pointer arithmetic is the foundation of array traversal in C. Understanding it lets you write efficient code for processing buffers, implementing data structures, and working with memory-mapped hardware. The equivalence between arr[i] and *(arr + i) is central to C's design philosophy of giving programmers direct memory control.

Real-World Use

The memcpy and memmove functions use pointer arithmetic internally. Audio and video processing code uses pointer arithmetic to navigate sample buffers. String functions like strchr and strstr use pointer arithmetic to scan memory. Device drivers use it to access memory-mapped registers at specific offsets.

What You Will Learn

  • How adding an integer to a pointer moves it by type-size steps
  • Traversing arrays using pointer arithmetic
  • Computing the difference between Two Pointers
  • Comparing pointers with relational operators
  • The relationship between arrays and pointers

Learning Path

flowchart LR
  A[Pointers Basics] --> B[Pointer Arithmetic
You are here] B --> C[Dynamic Memory] C --> D[Structs] D --> E[Memory Layout] style B fill:#f90,color:#fff

How Pointer Arithmetic Works

When you add an integer to a pointer, the compiler multiplies the integer by the size of the pointed-to type:

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // Points to arr[0]
    
    printf("arr[0]: %p -> %d\n", ptr, *ptr);
    printf("arr[1]: %p -> %d\n", ptr + 1, *(ptr + 1));
    printf("arr[2]: %p -> %d\n", ptr + 2, *(ptr + 2));
    printf("arr[3]: %p -> %d\n", ptr + 3, *(ptr + 3));
    printf("arr[4]: %p -> %d\n", ptr + 4, *(ptr + 4));
    
    // Each step is sizeof(int) = 4 bytes
    
    return 0;
}

Expected output (addresses vary):

arr[0]: 0x7fff12345670 -> 10
arr[1]: 0x7fff12345674 -> 20
arr[2]: 0x7fff12345678 -> 30
arr[3]: 0x7fff1234567c -> 40
arr[4]: 0x7fff12345680 -> 50

Note that the addresses are 4 bytes apart, not 1. The compiler automatically scales the arithmetic by sizeof(int).

Array Traversal with Pointers

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    // Forward traversal
    printf("Forward: ");
    int *ptr = arr;
    for (int i = 0; i < size; i++) {
        printf("%d ", *ptr);
        ptr++;  // Move to next element
    }
    printf("\n");
    
    // Backward traversal
    printf("Backward: ");
    ptr = &arr[size - 1];
    for (int i = size; i > 0; i--) {
        printf("%d ", *ptr);
        ptr--;  // Move to previous element
    }
    printf("\n");
    
    return 0;
}

Expected output:

Forward: 10 20 30 40 50
Backward: 50 40 30 20 10

Pointer Post-Increment and Pre-Increment

Like regular variables, pointers support ++ and -- operators:

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30};
    int *ptr = arr;
    
    // Post-increment: use value, then move
    printf("Post-increment:\n");
    printf("%d ", *ptr++);  // Prints 10, then moves to arr[1]
    printf("%d ", *ptr++);  // Prints 20, then moves to arr[2]
    printf("%d\n", *ptr);    // Prints 30
    // Output: 10 20 30
    
    ptr = arr;  // Reset
    
    // Pre-increment: move, then use value
    printf("Pre-increment:\n");
    printf("%d ", *++ptr);  // Moves to arr[1], prints 20
    printf("%d ", *++ptr);  // Moves to arr[2], prints 30
    printf("%d\n", *ptr);    // Prints 30
    // Output: 20 30 30
    
    return 0;
}

Pointer Difference

Subtracting two pointers of the same type gives the number of elements between them:

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50, 60, 70, 80};
    
    int *start = &arr[2];  // Points to 30
    int *end = &arr[6];    // Points to 70
    
    int diff = end - start;  // Number of elements between them
    printf("Elements between: %d\n", diff);  // 4
    
    // Verify by printing the elements
    printf("Elements: ");
    for (int *p = start; p <= end; p++) {
        printf("%d ", *p);
    }
    printf("\n");
    // Output: 30 40 50 60 70
    
    // Byte difference (using cast to char*)
    long byte_diff = (char*)end - (char*)start;
    printf("Byte difference: %ld\n", byte_diff);  // 16 (4 ints * 4 bytes)
    
    return 0;
}

Expected output:

Elements between: 4
Elements: 30 40 50 60 70
Byte difference: 16

Pointer Comparison

You can compare pointers using relational operators:

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *start = arr;
    int *end = arr + 4;  // Points to last element
    
    // Check if pointers are in range
    int *ptr = &arr[2];
    
    if (ptr >= start && ptr <= end) {
        printf("Pointer is within array bounds.\n");
    }
    
    // Iterate using pointer comparison
    printf("Elements: ");
    for (int *p = start; p <= end; p++) {
        printf("%d ", *p);
    }
    printf("\n");
    
    // NULL check
    int *null_ptr = NULL;
    if (null_ptr == NULL) {
        printf("Pointer is NULL.\n");
    }
    
    return 0;
}

Arrays and Pointers Relationship

In C, arrays and pointers are closely related but not identical:

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;
    
    // arr[i] is equivalent to *(arr + i)
    printf("arr[2] = %d\n", arr[2]);        // 30
    printf("*(arr + 2) = %d\n", *(arr + 2));  // 30
    
    // ptr[i] is also valid
    printf("ptr[2] = %d\n", ptr[2]);        // 30
    
    // But sizeof differs!
    printf("sizeof(arr): %zu\n", sizeof(arr));  // 20 (5 * 4)
    printf("sizeof(ptr): %zu\n", sizeof(ptr));  // 8 (pointer)
    
    // And you cannot assign to an array name
    // arr = ptr;  // ERROR: arr is not a modifiable lvalue
    
    return 0;
}

Expected output:

arr[2] = 30
*(arr + 2) = 30
ptr[2] = 30
sizeof(arr): 20
sizeof(ptr): 8

Pointer Arithmetic with Different Types

The step size depends on the pointed-to type:

#include <stdio.h>

int main() {
    char carr[] = "Hello";
    int iarr[] = {1, 2, 3};
    double darr[] = {1.1, 2.2, 3.3};
    
    printf("char* increments by 1 byte:\n");
    char *cp = carr;
    for (int i = 0; i < 5; i++) {
        printf("  +%d: %p -> '%c'\n", i, cp + i, *(cp + i));
    }
    
    printf("int* increments by %zu bytes:\n", sizeof(int));
    int *ip = iarr;
    for (int i = 0; i < 3; i++) {
        printf("  +%d: %p -> %d\n", i, ip + i, *(ip + i));
    }
    
    printf("double* increments by %zu bytes:\n", sizeof(double));
    double *dp = darr;
    for (int i = 0; i < 3; i++) {
        printf("  +%d: %p -> %.1f\n", i, dp + i, *(dp + i));
    }
    
    return 0;
}

Common Mistakes

1. Off-by-One with Pointer Arithmetic

int arr[5];
int *end = arr + 5;  // Points past the last element (OK for comparison)
*end = 42;           // ERROR: writing past array bounds

Pointing one past the end is valid for comparison, but dereferencing is not.

2. Subtracting Pointers of Different Types

int *ip;
double *dp;
// ptrdiff = ip - dp;  // ERROR: incompatible types

You can only subtract pointers of the same type (or cast them first).

3. Confusing Array Index with Pointer Arithmetic

int arr[5];
int *ptr = arr;
*(ptr + 5) = 42;  // Same as arr[5] -- out of bounds!

4. Modifying Array Name

int arr[10];
arr++;  // ERROR: array name is not a modifiable lvalue

You can modify a pointer variable but not the array name itself.

5. Assuming Pointer Arithmetic Works on void*

void *vp;
// vp++;  // ERROR: cannot increment void* (in GCC extension, moves by 1)

In standard C, you cannot perform arithmetic on void*. Cast to char* first for byte-level access.

Practice Questions

  1. If int *p points to arr[0], what does p + 3 point to? It points to arr[3]. The compiler adds 3 * sizeof(int) bytes to the address.

  2. What is the result of subtracting two pointers? The number of elements between them (not bytes).

  3. Can you compare pointers with relational operators? Yes. You can use <, <=, >, >= to check if one pointer is before or after another in memory.

  4. How many bytes does p++ move if p is a double*? 8 bytes (sizeof(double) on most systems).

  5. Challenge: Write a program that reverses an array using pointer arithmetic (no index notation).

Mini Project: Array Reversal with Pointers

#include <stdio.h>

void reverse(int *start, int *end) {
    while (start < end) {
        int temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    printf("Original: ");
    for (int *p = arr; p < arr + size; p++) {
        printf("%d ", *p);
    }
    printf("\n");
    
    reverse(arr, arr + size - 1);
    
    printf("Reversed: ");
    for (int *p = arr; p < arr + size; p++) {
        printf("%d ", *p);
    }
    printf("\n");
    
    return 0;
}

FAQ

Why does pointer arithmetic multiply by the type size?

Because memory is byte-addressable, but a pointer to int should move to the next int, not the next byte. The compiler scales the offset automatically.

Can I subtract two pointers that point to different arrays?

It is technically possible (the result is the byte difference), but the result is undefined behavior. Only subtract pointers within the same array.

What is the difference between arr and &arr?

arr is a pointer to arr[0] (int*). &arr is a pointer to the entire array (int(*)[5]). They have the same address but different types.

Can I use pointer arithmetic with void pointers?

Not in standard C. GCC allows it as an extension (moves by 1 byte). Use char* for byte-level arithmetic.

What does ptr[-1] mean?

It accesses the element before the one ptr points to. Negative indices are valid as long as they stay within the array bounds.

What is Next

Now that you understand pointer arithmetic, proceed to Functions and Pointers to learn how pointers are passed to functions and how function pointers work.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro

Home Browse C