C Pointer Arithmetic — Increment, Decrement, Array Traversal, and Pointer Difference
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
If
int *ppoints to arr[0], what doesp + 3point to? It points to arr[3]. The compiler adds 3 * sizeof(int) bytes to the address.What is the result of subtracting two pointers? The number of elements between them (not bytes).
Can you compare pointers with relational operators? Yes. You can use <, <=, >, >= to check if one pointer is before or after another in memory.
How many bytes does
p++move if p is a double*? 8 bytes (sizeof(double) on most systems).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
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.