How Address Operators Work in C++ - dummies

How Address Operators Work in C++

By Stephen R. Davis

Like the saying goes, “Everyone has to be somewhere.” Every C++ variable is stored somewhere in the computer’s memory. Memory is broken into individual bytes, with each byte carrying its own address numbered 0, 1, 2, and so on.

A variable intReader might be at address 0x100, whereas floatReader might be over at location 0x180. (By convention, memory addresses are expressed in hexadecimal.) Of course, intReader and floatReader might be somewhere else in memory entirely — only the computer knows for sure and only at the time that the program is executed.

This is somewhat analogous to a hotel. When you make your reservation, you may be assigned room 0x100. Your buddy may be assigned 80 doors down in room 0x180. Each variable is assigned an address when it is created.

The two pointer-related operators are shown in this table. The & operator says “tell me your address,” and * says “the value at the following address.”

Pointer Operators
Operator Meaning
& (unary) (In an expression) the address of
& (unary) (In a declaration) reference to
* (unary) (In an expression) the thing pointed at by
* (unary) (In a declaration) pointer to

These are not to be confused with the binary & and * operators.

The following Layout program demonstrates how the & operator can be used to display the layout of variables in memory:

// Layout - this program tries to give the
//          reader an idea of the layout of
//          local memory in her compiler
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
    int  start;
    int    n; long    l; long long   ll;
    float  f; double  d; long double ld;
    int  end;
    // set output to hex mode
    cout.setf(ios::hex);
    cout.unsetf(ios::dec);
    // output the address of each variable
    // in order to get an idea of how variables are
    // laid out in memory
    cout << "--- = " << &start << endl;
    cout << "&n  = " << &n     << endl;
    cout << "&l  = " << &l     << endl;
    cout << "&ll = " << &ll    << endl;
    cout << "&f  = " << &f     << endl;
    cout << "&d  = " << &d     << endl;
    cout << "&ld = " << &ld    << endl;
    cout << "--- = " << &end   << endl;
    // wait until user is ready before terminating program
    // to allow the user to see the program results
    cout << "Press Enter to continue..." << endl;
    cin.ignore(10, 'n');
    cin.get();
    return 0;
}

The program declares a set of variables of different types. It then applies the & operator to each one to find out its address. The results of one execution of this program with Code::Blocks appear as follows:

--- = 0x28fefc
&n  = 0x28fef8
&l  = 0x28fef4
&ll = 0x28fee8
&f  = 0x28fee4
&d  = 0x28fed8
&ld = 0x28fec0
--- = 0x28febc
Press Enter to continue...

Your results may vary. The absolute address of program variables depends on a lot of factors. The C++ standard certainly doesn’t specify how variables are to be laid out in memory.

Notice how the variable n is exactly 4 bytes from the first variable declared (start), which corresponds to the size of an int (4 bytes). Similarly, the variable l appears 4 bytes down from that, which is also the size of a long.

However, the float variable f is a full 12 bytes from its neighboring variable d (0x28fee4 – 0x28fed8 = 0x000c). That’s way more than the 4 bytes required for a float.

There is no requirement that the C++ compiler pack variables in memory with no spaces between them. In fact, you often see these gaps in memory when mixing variables of different size.

The Code::Blocks/gcc compiler could be storing variables for its own use in between your variables. Or, more likely, a peculiarity in the way the variables are being laid out in memory is causing the compiler to waste a small amount of space.