Lesson 1 of 6
Every variable your program creates lives somewhere in memory. Memory is one enormous numbered row of bytes, and the number of the byte where a variable starts is its address.
That is the whole idea. Everything else in this module is notation for it.
The row of boxes
Picture memory as a street of houses, each holding one byte, each with a house number:
address: 1000 1001 1002 1003 1004 1005 1006 1007
+------+------+------+------+------+------+------+------+
value: | 42 | 0 | 0 | 0 | 7 | 0 | 0 | 0 |
+------+------+------+------+------+------+------+------+
\___________________/ \___________________/
int x = 42 int y = 7
at address 1000 at address 1004
An int is 4 bytes (lesson 3.2), so x occupies 1000–1003 and y occupies 1004–1007. The
address of a variable is where it starts: x is "at 1000", not "at 1000 through 1003."
The real numbers are much larger and differ every run. The shape is what matters.
Taking an address
The & operator answers "where does this live?":
#include <iostream>
int main() {
int x = 42;
int y = 7;
std::cout << "x holds " << x << "\n";
std::cout << "y holds " << y << "\n";
// &x is the address of x. Printing it gives a number that changes every run,
// so compare instead of printing.
std::cout << "x and y are at different addresses: " << (&x != &y) << "\n";
std::cout << "an address is " << sizeof(&x) << " bytes on this machine\n";
return 0;
}
x holds 42
y holds 7
x and y are at different addresses: 1
an address is 8 bytes on this machine
Two things to take from that output.
Addresses are values. &x produces a number you can store, pass to a function, and compare —
just like 42 is a number. That is the entire premise of pointers (lesson 7.2).
An address is 8 bytes here. Not 4, not the size of an int. On a 64-bit machine an address
is 64 bits regardless of what it points at. The address of a char and the address of a
1000-element array are the same size, because both are just house numbers.
Why the numbers change every run
Print an actual address twice, on two runs, and you will usually get different values. That is deliberate: modern operating systems randomise where a program's memory is placed (address space layout randomisation) to make attacks harder.
So never write a program whose behaviour depends on a specific address, and never write a lesson whose expected output contains one — which is why every example here compares addresses rather than printing them.
Addresses are ordered, but only within one object
You can compare addresses with < and >. Within a single array the result is meaningful:
#include <iostream>
int main() {
int values[4] = {10, 20, 30, 40};
std::cout << (&values[0] < &values[1]) << "\n";
std::cout << (&values[3] > &values[0]) << "\n";
// Elements sit next to each other, so the gap between neighbours is one int.
std::cout << (&values[1] - &values[0]) << "\n";
return 0;
}
1
1
1
That last line is the surprise: &values[1] - &values[0] is 1, not 4. Subtracting addresses
counts elements, not bytes. Lesson 7.4 is entirely about why.
Comparing addresses of two unrelated variables (&x < &y for separate locals) is not
meaningful — the compiler is free to lay them out in any order, and the standard does not define
the comparison. Do not build logic on it.
What this buys you
A value you can hold that says "the thing over there" unlocks four things you cannot do otherwise:
- Let a function change its caller's variable rather than a copy (lesson 5.3 did this with references; now you will see what a reference is made of).
- Pass something large without copying it — an address is 8 bytes however big the object is.
- Ask for memory while the program is running, when you do not know at compile time how much you need (lesson 8.3).
- Say "nothing here" — an address that deliberately points at no object (lesson 7.2).
Try it
Declare an int, a double, a char, and an array of 10 ints. Print the sizeof of each
variable and the sizeof of each variable's address. Predict the numbers before you run it.
Checkpoint
- Memory is one long numbered sequence of bytes; a variable's address is where it starts.
&xyields the address ofx, as a value you can store, pass, and compare.- An address is 8 bytes on a 64-bit machine, regardless of what it points at.
- Real address values change between runs; never depend on a specific one.
- Subtracting two addresses in the same array counts elements, not bytes.
Questions about this lesson
Log in to ask a question.