|

One
of the principal hurdles for new programmers is
grappling with the many layers of intellectual abstraction.
Computers, of course, are just electronic machines.
They don’t know about windows and menus, they don’t
know about programs or instructions, and they don’t
even know about 1s and 0s. All that is really going
on is that voltage is being measured at various
places on an integrated circuit. Even this is an
abstraction: electricity itself is just an intellectual
concept, representing the behavior of subatomic
particles.
Few
programmers bother much with any level of detail
below the idea of values in RAM. After all, you
don’t need to understand particle physics to drive
a car, make toast, or hit a baseball, and you don’t
need to understand the electronics of a computer
to program one.
You
do need to understand how memory is organized, however.
Without a reasonably strong mental picture of where
your variables are when they are created, and how
values are passed among functions, it will all remain
an unmanageable mystery.
Partitioning
RAM
When
you begin your program, your operating system (such
as DOS or Microsoft Windows) sets up various areas
of memory based on the requirements of your compiler.
As a C++ programmer, you’ll often be concerned with
the global name space, the free store, the registers,
the code space, and the stack.
Global
variables are in global name space. We’ll talk more
about global name space and the free store in coming
chapters, but for now we’ll focus on the registers,
code space, and stack.
Registers
are a special area of memory built right into the
Central Processing Unit (or CPU). They take care
of internal housekeeping. A lot of what goes on
in the registers is beyond the scope of this book,
but what we are concerned about is the set of registers
responsible for pointing, at any given moment, to
the next line of code. We’ll call these registers,
together, the instruction pointer. It is the job
of the instruction pointer to keep track of which
line of code is to be executed next.
The
code itself is in code space, which is that part
of memory set aside to hold the binary form of the
instructions you created in your program. Each line
of source code is translated into a series of instructions,
and each of these instructions is at a particular
address in memory. The instruction pointer has the
address of the next instruction to execute. Figure
5.4 illustrates this idea.

Figure 5.4.The instruction pointer.
The
stack is a special area of memory allocated for
your program to hold the data required by each of
the functions in your program. It is called a stack
because it is a last-in, first-out queue, much like
a stack of dishes at a cafeteria, as shown in Figure
5.5.
Last-in,
first-out means that whatever is added to the stack
last will be the first thing taken off. Most queues
are like a line at a theater: the first one on line
is the first one off. A stack is more like a stack
of coins: if you stack 10 pennies on a tabletop
and then take some back, the last three you put
on will be the first three you take off.
When
data is "pushed" onto the stack, the stack grows;
as data is "popped" off the stack, the stack shrinks.
It isn’t possible to pop a dish off the stack without
first popping off all the dishes placed on after
that dish.

Figure 5.5. A stack.
A
stack of dishes is the common analogy. It is fine
as far as it goes, but it is wrong in a fundamental
way. A more accurate mental picture is of a series
of cubbyholes aligned top to bottom. The top of
the stack is whatever cubby the stack pointer (which
is another register) happens to be pointing to.
Each
of the cubbies has a sequential address, and one
of those addresses is kept in the stack pointer
register. Everything below that magic address, known
as the top of the stack, is considered to be on
the stack. Everything above the top of the stack
is considered to be off the stack and invalid. Figure
5.6 illustrates this idea.

Figure 5.6.The stack pointer.
When
data is put on the stack, it is placed into a cubby
above the stack pointer, and then the stack pointer
is moved to the new data. When data is popped off
the stack, all that really happens is that the address
of the stack pointer is changed by moving it down
the stack. Figure 5.7 makes this rule clear.

Figure 5.7. Moving the stack pointer.
|