Why Use Pointers
beginner
c++11
memory
Related: What Are Pointers and Why Use References
Pointers have many uses in C++ some of which include:
- Heap allocation
- You can do math with them
Heap Allocation
Most variables you use in C++ are on the stack. Stack variables live for the lifetime of the scope they are a part of which is usually a single function but can also be a for loop or an if statement. If you need a variable to live longer than a single function then you allocate that variable on the heap. This is very useful when the size of the variable is large or it’s expensive to create that variable, it makes sense to allocate large and expensive objects on the heap and pass a pointer to other functions than to recreate the same data. When allocating data on the heap the variable is located in heap memory which belongs to your program but not to any particular function. Because of this we only ever have pointers to memory on the heap:
#include <iostream> #include <string> struct Planet { std::string name; float distance; float radius; float mass; // We could have lots more here }; // We could also accept a "const Planet&" here instead // https://cppbyexample.com/why_references.html void describe_planet(Planet* planet) { std::cout << planet->name << ":\n" << " Distance from Sun: " << planet->distance << "\n" << " Radius: " << planet->radius << "\n" << " Mass: " << planet->mass << "\n"; } int main() { Planet* mars = new Planet{"Mars", 1.5, 3389.5, 6.4171e23}; if (!mars) { std::cout << "Unable to allocate memory for a new Planet\n"; return 1; } describe_planet(mars); // Everything created with "new" must also be "deleted" delete mars; }
Mars: Distance from Sun: 1.5 Radius: 3389.5 Mass: 6.4171e+23
If the changed syntax above is confusing, check out How Pointers Work in C++ for more details.
You Can Do Math with Pointers
One of the most powerful, and dangerous, features of pointers is that you can perform pointer math with them. When you add or subtract an integer to a pointer it changes what that pointer points to. You must be very careful with this. There’s no guardrails with pointer math and it’s very easy to accidentally make a pointer point to something you didn’t mean to. When this happens your program might crash but worst case the memory at the pointed to address looks “close enough” to what your program was expecting and it may just continue on for some time! Like I said, dangerous stuff. Here’s an example:
#include <iostream> #include <string> #include <array> struct Planet { std::string name; double distance; double radius; double mass; // We could have lots more here }; int main() { std::array<Planet, 4> planets; planets[0] = Planet{"Mercury", 0.4, 2439.7, 3.3011e23}; planets[1] = Planet{"Venus", 0.7, 6051.8, 4.8675e24}; planets[2] = Planet{"Earth", 1, 6371.0, 5.972e24}; planets[3] = Planet{"Mars", 1.5, 3389.5, 6.4171e23}; // std::array data() returns a pointer to the first element. // std::array *guarantees* the elements are next to each other // in memory. Otherwise this wouldn't work. Planet* firstPlanet = planets.data(); Planet* planet = firstPlanet; for (size_t i = 0; i < planets.size(); i++) { std::cout << planet->distance << "\n"; planet = planet + 1; // Same as planet++ or planet += 1; } std::cout << "We're now reading *after* the planets vector\n"; for (size_t i = 0; i < 4; i++) { std::cout << planet->radius<< "\n"; planet++; } }
0.4 0.7 1 1.5 We're now reading *after* the planets vector 0 2.23521e-314 2.235e-314 2.235e-314
What we just did in the first for loop is known as iteration.
In fact, when using the for-each
style for loop (for (Planet& p : planets)
) C++ is generating code for you that looks similar to the first for loop in the above example.
This has the added benefit of always correctly reading elements from the object you’re iterating and not accidentally reading garbage memory, such as in the second for loop above.