Dynamic memory
allocation in C++
So you have just finished your
program and you would like to see it at work. Usually you press a
combination of keys to compile and run it. But what actually
happens when you press those keys ? The compilation process
translates your code from C++ to machine language, which is the only language computers
"understand". Then your application is given a certain
amount of memory to use, which is divided into three segments as follows :
- Code Segment,
in which all the application code is stored
- Data Segment,
that holds the global data
- Stack Segment,
used as a container for local variables and other
temporary information.
In addition to these, the
operating system also provides an extra amount of memory called Heap.
Now let us recall what a C++
variable consisted of :
- name, an
identifier to recognize the variable
- type, the
set of values it may take
- scope, the
area of code in which it is visible
- address,
the address at which the variable is allocated
- size, the
amount of memory used to store its contents.
Consider the following sequence
of code :
void
cookie() {
int integer_X;
...
} |
Let us try to figure out what
are the attributes of the variable declared inside this function.
- name : integer_X
- type : int
- scope : local, only visible within the cookie function
- address :
a certain address in the stack segment, where the variable is allocated
- size : 32 bits (depending on
the compiler)
What is a pointer then ? We all heard about it, it is the
variable declared with a star in front of it... but let us try
and put some order in what we know by enumerating its exact
attributes :
- name : an
arbitrary identifier
- type : integer address
- scope
: local or global (depending on
the situation)
- address
: the address in the data segment (if it is
global) or stack segment (if it is local)
- size
: 32
bits
(16 bits for segment + 16 bits for offset
of the address it points to)
A dynamic variable is a
variable that is stored in the heap, outside the data and stack segments, that may
change size during runtime or may even disappear for good. In
fact if we do not allocate a certain amount of memory to store
its contents, it will never exist.
For example
consider the next declaration :
double
*dp;
This tells the
compiler we have a pointer dp that may hold the starting address of a dynamic
variable of type double. However, the dynamic variable does not exist yet
- to create it we must use the new operator like this :
dp = new
double;
Remember
one thing - dynamic variables are never initialized by the compiler. Therefore it
is good practice to first assign them a value, or your
calculations may not come out right. There are two ways of doing
this :
dp = new double;
*dp = a;
or
dp = new double(a);
where a is the initial value. I
personally recommend the second version as it is more suggestive
and also more compact.
Consider this line of code :
double *dp = new double(3.1415);
The diagram below shows the
possible connection between dp and the dynamic variable associated with it,
after the previous line is executed.

Now consider you
have decided to erase the dynamic variable for good from the
heap. Use the delete operator to achieve this :
delete dp;
Notice that while we have freed 8 bytes of memory - which is sizeof(double) - the dp pointer
was not erased. It still exists in the data or
stack segment of the application and we may use it to initialize
another dynamic variable.
C++ also provides the
possibility to allocate an entire array in the heap, keeping a
pointer to its first element. Again we use the new operator but mention the size of the
array in square brackets :
int *table;
table = new int[100];
|
This will allocate 100 * sizeof(int) =
100 * 4 = 400
bytes of memory and assign
the starting address of the memory block to the table pointer.
Arrays allocated in the heap are
similar to those allocated in the data or stack segments, so we
may access an arbitrary element using the indexing operator []. For example the next loop initializes
each element of the array to zero :
for (int i = 0; i < 100; ++i)
table[i] = 0;
|
Bad news is C++ does not provide
any method of initializing heap arrays as you would an ordinary
dynamic variable, so we have to do it ourselves using a loop
similar to the one above. The following line will generate errors
at compilation :
table = new int[100](0);
To erase a heap-allocated array
we will use the delete
operator, but this time add a pair of square brackets so that the
compiler can differentiate it from an ordinary dynamic variable.
delete [] table;
All we have learned so far are
means of replacing the old malloc()
and free() functions in C with their new and delete C++ analogues. The main reason is that they are
better alternatives to dynamic memory allocation and also have a
more compact syntax. However C pointer arithmetics and other
pointer operations are also available in C++.
Memory corruption
Memory is said to be corrupted
if we try one of the following :
- Free a dynamic variable
that has already been freed
char *str = new char[100];
delete [] str;
delete [] str;
|
- Free a dynamic variable
that has not been yet allocated
- Assign a certain value to a
dynamic variable that was never allocated
char *str;
strcpy(str, "error");
|
The previous
three examples will most probably cause the application to crash.
However the next two "bugs" are harder to detect :
- Assign a certain value to a
dynamic variable, after it has been freed (this may also
affect other data stored in the heap)
char *str = new char[100];
delete [] str;
char *test = new char[100];
strcpy(str, "surprise !");
cout << test;
delete [] test;
|
- Access an element with an
index out of range
char *str = new char[30];
str[40] = 'C';
|
Last but not
least, remember it is good practice to test whether allocation
was or was not successful before proceeding with the code. The
reason for this is that the operating system may run out of heap
at some point, or the memory may get too fragmented to allow
another allocation.
char *str = new char[512];
if (str == NULL) {
// unable to allocate block of memory !
}
|