Pointer arithmetic means adding an integer to a pointer, which moves the pointer that number of element sizes forward.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values;
std::cout << p << '\n';
std::cout << *p << '\n';
// Advance the pointer by this many array elements
p = p + 1;
std::cout << p << '\n';
std::cout << *p << '\n';
return 0;
}
An array of ints named values is declared, then p is assigned its first element. We print p both as an address, around 0x7ffd2a1c during normal execution, and as an integer 10. p = p + 1 assigns one element past its original position. The next address output will be 4 bytes higher, at 0x7ffd2a20 if ints are 4 bytes, and the value is 20.
The prefix and postfix increments behave almost the same way.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values;
std::cout << p << " holds " << *p << '\n';
// Increment the value before the expression uses it
++p;
std::cout << p << " holds " << *p << '\n';
return 0;
}
p was assigned the address of the first element. Its address and content are printed. p is then assigned the address of the element following it, and then printed again. The address of p has risen by one int.
Moving backwards from an address subtracts an element.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values + 3;
std::cout << p << " holds " << *p << '\n';
// Decrement the value before the expression uses it
--p;
std::cout << p << " holds " << *p << '\n';
return 0;
}
p is assigned an address pointing to the fourth element, then p is subtracted the value one int. The values are printed.
Adding a larger integer multiplies the number of elements by the size of one element.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values;
std::cout << p << '\n';
p = p + 3;
std::cout << p << '\n';
std::cout << *p << '\n';
return 0;
}
The address of p is first saved. Then p is added 3 to its current value. The address of p is now 12 bytes higher, the number of bytes of three ints, and we print that address, as well as the corresponding value 40. The subtraction p - start saves the difference between start and p in an int.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* start = values;
int* finish = values + 4;
std::cout << start << '\n';
std::cout << finish << '\n';
std::cout << finish - start << '\n';
return 0;
}
You must never go outside the boundaries of an array, not even to just read an invalid address without using it to access data.
#include <iostream>
int main()
{
int values[3]{10, 20, 30};
int* p = values;
std::cout << p << '\n';
// p = p + 4; // Undefined behavior
return 0;
}
This example takes a pointer and adds 4 to it, making it fall 4 integers out of the array of three ints. This is not guaranteed to compile and, if it does, it is very likely the compiler will ignore the addition and optimize it out.
By using an ever increasing pointer, one can move through all of the elements in an array.
#include <iostream>
int main()
{
int values[4]{10, 20, 30, 40};
int* p = values;
int* end = values + 4;
while (p != end)
{
std::cout << p << " holds " << *p << '\n';
++p;
}
return 0;
}
p is assigned the address of the first element, then end is assigned the address one past the last element. Each time we loop, we print the pointer and an int, followed by increasing the value of p. The value of p is an increment of 4 each time since they are ints. When p is equal to end, the loop breaks.
The value of the stride is the size of the object pointed to by the pointer.
#include <iostream>
int main()
{
double temps[3]{15.5, 18.0, 21.5};
double* p = temps;
std::cout << p << " holds " << *p << '\n';
++p;
std::cout << p << " holds " << *p << '\n';
return 0;
}
We again create an array and assign p the value of its first element, a double. In the first output, p holds the address and 15.5, which is a float. Then, when p is added the value of one integer, it takes eight more bytes since p now stores the address of the next double value 18.0.
Exercise: Pointer ArithmeticStarter code, hints and solutionOpenClose
Practice: Pointer Arithmetic
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Advance p by two elements instead of one and print its offset from values instead of the raw address. Predict the offsets and dereferenced values, keeping the pointer within the array.
Mission checklist
- Run the starter as a baseline, then predict the change requested in Your challenge.
- Make that change in your editor; use the lesson-specific hints if you need help.
- Compile and run your answer, then compare with the worked solution and explain the result.
Starter program
This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values;
std::cout << p << '\n';
std::cout << *p << '\n';
// Advance the pointer by this many array elements
p = p + 1;
std::cout << p << '\n';
std::cout << *p << '\n';
return 0;
}Hints
p + 1 advances by one int element, not one byte. Starting from values, that new pointer refers to the next initializer.
Predict the dereferenced values rather than exact printed addresses, which can change between runs. Keep arithmetic within this array and never dereference its one-past-end pointer.
Worked solution
The solution prints p - values instead of unstable numeric addresses, showing the element offset. After advancing p by two elements it has offset 2 and reads 30. Both addresses belong to the same array, making the subtraction valid.
#include <iostream>
int main()
{
int values[5]{10, 20, 30, 40, 50};
int* p = values;
std::cout << (p - values) << '\n';
std::cout << *p << '\n';
// Advance the pointer by this many array elements
p = p + 2;
std::cout << (p - values) << '\n';
std::cout << *p << '\n';
return 0;
}
Example output
0
10
2
30
0 comments
No comments yet. Be the first.