Pointer Arithmetic
Because a pointer holds a memory address, you can perform arithmetic on it — but that arithmetic behaves differently from ordinary number arithmetic. Adding 1 to a pointer does not add one byte; it advances the pointer by the size of whatever type it points to. This is what makes pointers so useful for walking through arrays.
Incrementing and decrementing a pointer
pointer_increment.cpp
#include <iostream>
int main() {
int numbers[4] = {10, 20, 30, 40};
int* p = numbers; // points to numbers[0]; array decays to a pointer
std::cout << *p << std::endl; // 10
p++; // moves forward by sizeof(int), NOT 1 byte
std::cout << *p << std::endl; // 20
p += 2;
std::cout << *p << std::endl; // 40
p--;
std::cout << *p << std::endl; // 30
return 0;
}Pointer arithmetic and array decay
array_pointer_equivalence.cpp
int numbers[4] = {10, 20, 30, 40};
std::cout << numbers[2] << std::endl; // 30
std::cout << *(numbers + 2) << std::endl; // 30 — identical result
// Walking an array using a pointer instead of an index:
for (int* p = numbers; p != numbers + 4; p++) {
std::cout << *p << " ";
}Comparing pointers
undefined_pointer_arithmetic.cpp
int arr[4] = {1, 2, 3, 4};
int other = 99;
int* p = arr + 10; // undefined behavior: far past the array's end
int* q = &other + 5; // undefined behavior: other isn't an array at all
int* end = arr + 4; // OK: one-past-the-end, valid to compute and compare
// int bad = *end; // NOT OK: dereferencing one-past-the-end is UBWhy this is rarely needed in modern code
Manual pointer arithmetic used to be the standard way to iterate over data in C and early C++. Modern C++ provides much safer alternatives that express the same intent without the risk of stepping outside valid memory:
modern_alternatives.cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {10, 20, 30, 40};
// Range-based for loop: no pointer arithmetic at all
for (int value : numbers) {
std::cout << value << " ";
}
std::cout << std::endl;
// Iterators: safer, container-aware "pointer-like" objects
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}p + n moves a pointer by n * sizeof(pointed-to type) bytes, not n bytes.
Pointer arithmetic is well-defined only within a single array (including one-past-the-end).
Prefer range-based for loops and iterators over manual pointer walking in new code.