C++ Tutorial
C++ Pointers
A pointer stores an address. * reads the value. & takes the address. Null means no object.
An address in a variable
A pointer holds the location of another object, not a copy of its value. int* p means “p stores the address of an int”. You get that address with &n. You read the integer at that address with *p.
A reference is an alias you cannot reseat. A pointer is a value you can inspect, copy, and set to “nothing”. Start with one integer and one pointer to it. That is enough for this chapter.
Point at an int
Declare the pointer, take the address, then dereference. The star in int* p is part of the type. The star in *p means “the int at this address”.
Example
#include <iostream>
using namespace std;
int main() {
int n = 7;
int* p = &n;
cout << *p << endl;
*p = 12;
cout << n << endl;
return 0;
}*p = 12 writes through the pointer. n becomes 12 because pholds the address of n. Printing p itself would show an address. You rarely need that number. You need *p.
nullptr means no object
A pointer can hold nullptr: a defined empty value, not a guess. Use it when you do not yet have an object, or when a function wants to say “none”. Always test before you dereference.
Example
#include <iostream>
using namespace std;
int main() {
int n = 4;
int* p = nullptr;
if (p == nullptr) {
cout << "no object yet" << endl;
}
p = &n;
if (p != nullptr) {
cout << *p << endl;
}
return 0;
}Prefer nullptr over the old NULL macro or a raw 0. C++17 code in this course writes nullptr.
Do not dereference nullptr
*p is only safe when p points at a live object. If p isnullptr, do not read or write *p. Do not invent an address. Do not leave a pointer uninitialized and then dereference it. Check, then use.
This chapter will not demonstrate a crash. There is nothing useful to learn from one. Initialize every pointer: either &n or nullptr. If you need “always an object”, use a reference instead.
Arrays decay to pointers (briefly)
In many expressions, the name of an array becomes a pointer to its first element. That is whyint* p = nums; compiles when nums is an array. It is the same as&nums[0].
Example
#include <iostream>
using namespace std;
int main() {
int nums[3] = {10, 20, 30};
int* p = nums;
cout << *p << endl;
cout << p[1] << endl;
return 0;
}p[1] is the slot after the first. Stay inside the array: p[1] is valid here,p[3] is not. You do not need pointer arithmetic beyond this. Index with a loop. Keep the length in a separate int. A pointer does not remember how many slots follow it.
Pointer versus reference
| Reference | Pointer | |
|---|---|---|
| Declare | int& r = x; | int* p = &x; |
| Use the value | r | *p |
| Can be empty | No | Yes, nullptr |
| Can reseat | No | Yes, p = &other; |
Pick a reference when the object must exist for the whole use. Pick a pointer when absence is a real state, and then test for nullptr. Heap allocation with new is a later chapter. You do not need it to understand addresses.
Keep pointers boring
One object, one pointer, one check for null. That pattern will carry you through function parameters and data structures. Next: put work in a function so you do not copy-paste the same block.
Example
#include <iostream>
using namespace std;
void printIfSet(int* p) {
if (p == nullptr) {
cout << "no value" << endl;
return;
}
cout << *p << endl;
}
int main() {
int n = 42;
int* ok = &n;
int* empty = nullptr;
printIfSet(ok);
printIfSet(empty);
return 0;
}Worked examples
The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.
Open them in the C++ editor at /cpp/try. Change one measurement and check whether the result still has the right unit.
Physics
Swap two velocities
In a simple 1D collision sketch you sometimes exchange the two speeds. A swap of v1 and v2 is that exchange. Pointers hold the addresses; *p and *q are the values.
Example
#include <iostream>
using namespace std;
int main() {
double v1 = 5.0;
double v2 = -2.0;
double *p = &v1;
double *q = &v2;
double tmp = *p;
*p = *q;
*q = tmp;
cout << "v1 = " << v1 << ", v2 = " << v2 << endl;
return 0;
}Maths
Double a length in place
Similar figures scale by a factor. Doubling every length quadruples area. Here only one length is stored, and *p = *p * 2.0 writes back into that same variable.
Example
#include <iostream>
using namespace std;
int main() {
double length = 1.2;
double *p = &length;
*p = *p * 2.0;
cout << "length = " << length << " m" << endl;
return 0;
}