Pointer Arithmetic in C
Add and subtract with pointers! Learn how pointer math works with arrays and why ptr++ moves by the size of the data type.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Understand pointer increment/decrement
- ✓Know why ptr++ moves by sizeof(type)
- ✓Use pointers to traverse arrays
- ✓Calculate pointer differences
?Why Use Pointer Arithmetic?
Arrays and pointers are deeply connected in C. Pointer arithmetic lets you traverse arrays and manipulate memory efficiently:
Array Traversal
arr[i] ↔ *(arr + i)
Performance
Pointer incrementing (ptr++) can be faster than array indexing in some cases.
String Processing
Walk through strings
Buffer Handling
Navigate memory buffers
Data Structures
Build linked lists, trees
01What is Pointer Arithmetic?
➕ Simple Definition
Pointer arithmetic lets you perform math operations on pointers. When you add 1 to a pointer, it moves to the next element, not the next byte!
The Key Rule
ptr + 1 = ptr + sizeof(*ptr)
Adding 1 moves by the SIZE of the data type, not 1 byte!
Visualizing ptr + 1 for int* (4 bytes)
arr[0]
0x1000
arr[1]
0x1004
arr[2]
0x1008
ptr = 0x1000 → ptr + 1 = 0x1004 → ptr + 2 = 0x1008
Each int is 4 bytes, so +1 moves by 4 bytes!
| Data Type | Size | ptr + 1 moves by | Example |
|---|---|---|---|
| char* | 1 byte | 1 byte | 0x1000 → 0x1001 |
| int* | 4 bytes | 4 bytes | 0x1000 → 0x1004 |
| double* | 8 bytes | 8 bytes | 0x1000 → 0x1008 |
Why This Matters
This "smart" pointer arithmetic is what makes arrays and pointers interchangeable in C. The compiler automatically multiplies by sizeof(type), so you can think in terms of elements, not bytes!
02Pointer Arithmetic Operations
| Operation | Syntax | Description |
|---|---|---|
| Increment | ptr++ | Move to next element |
| Decrement | ptr-- | Move to previous element |
| Addition | ptr + n | Move n elements forward |
| Subtraction | ptr - n | Move n elements backward |
| Difference | ptr1 - ptr2 | Number of elements between |
1#include <stdio.h>23int main() {4 int arr[] = {10, 20, 30, 40, 50};5 int* ptr = arr; // Points to first element6 7 printf("Array: ");8 for (int i = 0; i < 5; i++) {9 printf("%d ", arr[i]);10 }11 printf("\n\n");12 13 // ptr points to arr[0]14 printf("*ptr = %d (element at ptr)\n", *ptr);15 16 // ptr + 1 points to arr[1]17 printf("*(ptr + 1) = %d (next element)\n", *(ptr + 1));18 19 // ptr + 2 points to arr[2]20 printf("*(ptr + 2) = %d (2nd next)\n", *(ptr + 2));21 22 // Increment pointer23 ptr++; // Now points to arr[1]24 printf("\nAfter ptr++:\n");25 printf("*ptr = %d\n", *ptr);26 27 // Decrement pointer28 ptr--; // Back to arr[0]29 printf("\nAfter ptr--:\n");30 printf("*ptr = %d\n", *ptr);31 32 // Pointer difference33 int* start = &arr[0];34 int* end = &arr[4];35 printf("\nElements between start and end: %ld\n", end - start);36 37 return 0;38}Array: 10 20 30 40 50
*ptr = 10 (element at ptr)
*(ptr + 1) = 20 (next element)
*(ptr + 2) = 30 (2nd next)
After ptr++:
*ptr = 20
After ptr--:
*ptr = 10
Elements between start and end: 4
03Arrays and Pointers Relationship
The Secret: They're the Same!
In C, the array name is just a pointer to the first element. The [] operator is really pointer arithmetic in disguise!
arr[i]
Array subscript
=
*(arr + i)
Pointer arithmetic
How arr[2] Really Works
Step 1: Convert to pointer notation → Step 2: Calculate address → Step 3: Dereference
1#include <stdio.h>23int main() {4 int arr[] = {10, 20, 30, 40, 50};5 6 printf("Array notation vs Pointer notation:\n\n");7 8 for (int i = 0; i < 5; i++) {9 printf("arr[%d] = %d | *(arr + %d) = %d\n", 10 i, arr[i], i, *(arr + i));11 }12 13 printf("\nAddresses:\n");14 for (int i = 0; i < 5; i++) {15 printf("&arr[%d] = %p | arr + %d = %p\n", 16 i, (void*)&arr[i], i, (void*)(arr + i));17 }18 19 return 0;20}Array notation vs Pointer notation:
arr[0] = 10 | *(arr + 0) = 10
arr[1] = 20 | *(arr + 1) = 20
arr[2] = 30 | *(arr + 2) = 30
arr[3] = 40 | *(arr + 3) = 40
arr[4] = 50 | *(arr + 4) = 50
04Practical: Iterating with Pointers
1#include <stdio.h>23// Sum array using pointer arithmetic4int sumArray(int* arr, int size) {5 int sum = 0;6 int* end = arr + size; // Pointer to one past last element7 8 while (arr < end) {9 sum += *arr; // Add current element10 arr++; // Move to next11 }12 return sum;13}1415// Reverse array in place using pointers16void reverseArray(int* arr, int size) {17 int* start = arr;18 int* end = arr + size - 1;19 20 while (start < end) {21 // Swap22 int temp = *start;23 *start = *end;24 *end = temp;25 26 start++;27 end--;28 }29}3031int main() {32 int numbers[] = {1, 2, 3, 4, 5};33 int size = 5;34 35 printf("Original: ");36 for (int i = 0; i < size; i++) printf("%d ", numbers[i]);37 printf("\n");38 39 printf("Sum: %d\n", sumArray(numbers, size));40 41 reverseArray(numbers, size);42 printf("Reversed: ");43 for (int i = 0; i < size; i++) printf("%d ", numbers[i]);44 printf("\n");45 46 return 0;47}Original: 1 2 3 4 5
Sum: 15
Reversed: 5 4 3 2 1
05Pointer Subtraction: Finding Distance
Measuring Elements Between Pointers
Subtracting two pointers gives you the number of elementsbetween them, not the byte difference. The result is of type ptrdiff_t.
# ptr2 - ptr1 = Element Count
ptr1
[0]
[1]
[2]
ptr2
[3]
[4]
ptr2 - ptr1 = 3
There are 3 elements between ptr1 and ptr2
1#include <stdio.h>23int main() {4 int arr[] = {10, 20, 30, 40, 50};5 6 int* ptr1 = &arr[0]; // Points to 107 int* ptr2 = &arr[3]; // Points to 408 9 // Pointer subtraction = element count10 printf("ptr2 - ptr1 = %ld elements\n", ptr2 - ptr1); // 311 12 // Useful for finding string length!13 char str[] = "Hello";14 char* start = str;15 char* end = str;16 while (*end != '\0') end++;17 18 printf("String length: %ld\n", end - start); // 519 20 return 0;21}ptr2 - ptr1 = 3 elements
String length: 5
!Code Pitfalls: Common Mistakes & What to Watch For
These are the most common mistakes that trip up beginners. Study them carefully to avoid hours of debugging!
Going out of bounds
Accessing memory outside the array is undefined behavior — it might crash, corrupt data, or "work" but be silently wrong!
int arr[5];
int* ptr = arr + 10; // Danger!
int arr[5];
int* ptr = arr + 4; // ✓ Last element
Adding two pointers together
You can subtract pointers (to get element count), but adding pointers makes no sense!
int* p3 = p1 + p2; // Invalid!
int diff = p2 - p1; // ✓ Valid
Forgetting operator precedence
* and ++ have tricky precedence!
// These are DIFFERENT:
*ptr++ // Dereference, THEN increment ptr
(*ptr)++ // Dereference, THEN increment VALUE
*++ptr // Increment ptr, THEN dereference
Watch Out When Copying Code!
Common Mistakes with Pointer Arithmetic
Copying code frequently generate dangerous pointer arithmetic code:
- ✗Off-by-one errors: Code often uses
ptr + sizeand dereferences it, accessing one past the last valid element - ✗Wrong type scaling: Beginners often calculate byte offsets manually instead of letting pointer type handle scaling
- ✗Precedence mistakes: Copied code
*ptr++when meaning(*ptr)++, causing iterator bugs - ✗Invalid pointer comparisons: Beginners often compare pointers from different arrays, which is undefined behavior
Always Understand Before Using
When you may copy pointer arithmetic, trace through manually: What is ptr pointing to? After ptr + n, is the result still within the array? Is the type correct? Pointer arithmetic bugs cause crashes, security vulnerabilities, and silent data corruption that may only appear in production.
08Frequently Asked Questions
Q:Why does ptr++ move by 4 bytes for int* but 1 for char*?
A: The pointer type determines the "step size." int* steps bysizeof(int) = 4 bytes to reach the next integer.char* steps by 1 byte. This is why pointer types matter — they define how arithmetic works.
Q:Why can't I add two pointers together?
A: Adding addresses doesn't make sense — what would "address 1000 + address 2000" mean? However, subtracting pointers is valid: it gives the number of elements between them. You can add/subtract integers to/from pointers for navigation.
Q:What's the difference between *ptr++ and (*ptr)++?
A: *ptr++: Get the value, then increment the pointer. (*ptr)++: Get the value, then increment the value (pointer unchanged). Precedence matters!++ binds tighter than *, so *ptr++ is *(ptr++).
Q:Is arr[i] the same as *(arr + i)?
A: Yes! The [] operator is just syntactic sugar. arr[i] is converted to*(arr + i) by the compiler. This is whyi[arr] also works (same as *(i + arr)) — though please don't write code like that!
Q:Can I compare pointers with < and >?
A: Yes, but only for pointers to the same array or one past the end. p1 < p2 tells you if p1 comes before p2 in the array. Comparing unrelated pointers is undefined behavior — the result is meaningless.
08Summary
Key Takeaways
- •ptr + n: Moves by n × sizeof(type) bytes
- •arr[i] = *(arr + i): Same thing!
- •ptr2 - ptr1: Element count between
- •ptr1 + ptr2: Invalid! Can't add pointers
Quick Reference
// Movement
ptr++ // Next element
ptr-- // Previous
ptr + 5 // 5 elements ahead
// Access
*ptr // Value at ptr
*(ptr+i) // Same as arr[i]
// Distance
p2 - p1 // Elements between
Pointer Arithmetic at a Glance
ptr
Current
+1
→
ptr+1
+sizeof(type)
+1
→
ptr+2
+2×sizeof(type)
10Practical Tips
Array Notation vs Pointer Notation
arr[i] and *(arr+i)are completely equivalent. Use array notation for clarity when indexing, pointer notation when iterating with a moving pointer.
One Past the End is Valid
You can point to one element past the end of an array for comparison purposes (while (p != end)). You just can't dereference it. This is how iterator patterns work in C.
Void Pointer Arithmetic
Standard C doesn't allow arithmetic on void* because the size is unknown. Cast to char* for byte-level operations. GCC allows void* arithmetic as an extension, treating it as char*, but this isn't portable.
Test Your Knowledge
Related Tutorials
Dynamic Memory Allocation
Allocate memory at runtime! Use malloc, calloc, realloc, and free. Create arrays whose size you don't know until the program runs.
Structures and Dynamic Memory
Combine structs with malloc! Create dynamic arrays of structures that grow as needed. Build real data structures.
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!