Dynamic Memory Allocation

Author gives a brief  idea about how dynamic memory allocation works in this article.

Working with a fixed set of variables in a program can be very restrictive. The need often arises within an application to decide the amount of space to be allocated for storing different types of variables at execution time, depending on the input data for the program. With one set of data it may be appropriate to use a large integer array in a program, whereas with a different set of input data, a large floating point array may be required. Obviously, since any dynamically allocated variables can't have been defined at compile time, they can't be named in your source program. When they are created, they are identified by their address in memory which is contained within a pointer. With the power of pointers and the dynamic memory management tools in Visual C++, writing your programs to have this kind of flexibility is quick and easy.

The Free Store, Alias the Heap

In most instances, when your program is executed there is unused memory in your computer. This unused memory is called the heap in C++, or sometimes the free store. You can allocate space within the free store for a new variable of a given type using a special operator in C++ which returns the address of the space allocated. This operator is new, and it's complemented by the operator delete, which de-allocates memory previously allocated by new.

You can allocate space in the free store for some variables in one part of a program, and then release the allocated space and return it to the free store once you have finished with the variables concerned. This makes the memory available for reuse by other dynamically allocated variables, later in the same program.

You would want to use memory from the free store whenever you need to allocate memory for items that can only be determined at run time. One example of this might be allocating memory to hold a string entered by the user of your application. There is no way you can know in advance how large this string will need to be, so you would allocate the memory for the string at run time, using the new operator. Later, we'll look at an example of using the free store to dynamically allocate memory for an array, where the dimensions of the array are determined by the user at run time.

This can be a very powerful technique; it enables you to use memory very efficiently, and in many cases, it results in programs that can handle much larger problems, involving considerably more data than otherwise might be possible.

The Operators new and delete

Suppose that we need space for a double variable. We can define a pointer to type double and then request that the memory be allocated at execution time. We can do this using the operator new with the following statements:

double* pvalue = NULL;    // Pointer initialized with null
pvalue = new double;      // Request memory for a double variable

This is a good moment to recall that all pointers should be initialized. Using memory dynamically typically involves a number of pointers floating around, so it's important that they should not contain spurious values. You should try to arrange that if a pointer doesn't contain a legal address value, it is set to NULL.

The new operator in the second line of code above should return the address of the memory in the free store allocated to a double variable, and this address will be stored in the pointer pvalue. We can then use this pointer to reference the variable using the indirection operator as we have seen. For example, we could set the value of the double variable to 9999.0 with the statement:

*pvalue = 9999.0;

However, using a dynamic variable as shown here is very risky. The memory may not have been allocated, if the free store had been used up. Alternatively, it could be that the free store is fragmented by previous usage, so there wasn't a sufficient number of contiguous bytes to accommodate the variable for which you want to obtain space. In this case, the operator new will return a NULL pointer value, so before using it we should always test for a valid address being returned and stored in our pointer. We could have done this by writing the following:

if(!(pvalue = new double))
   cout << endl
        << "Out of memory.";

Here, we have called for the space to be allocated and the address to be stored in the pointer, pvalue, all within the if statement. If a NULL pointer value was returned, the if expression will be true, so the message will be displayed and the exit() function called to end the program. The exit() function is used when you want to terminate a program abnormally. The value between the parentheses is an integer (int) value that can be used to indicate the circumstances under which the program was terminated. If you use the exit() function, you should #include the header file cstdlib into your program.
You can also initialize a variable created by new. Taking our example of the double variable which was allocated by new and the address stored in pvalue, we could have set the value to 999.0 as it was created with this statement:

pvalue = new double(999.0); // Allocate double and initialize it

When you no longer need a variable that has been dynamically allocated, you can free up the memory that it occupies in the free store with the delete operator:

delete pvalue;        // Release memory pointed to by pvalue

This ensures that the memory can be used subsequently by another variable. If you don't use delete, and subsequently store a different address value in the pointer pvalue, it will be impossible to free up the memory or to use the variable that it contains, since access to the address will have been lost.

Allocating Memory Dynamically for Arrays

Allocating memory for an array dynamically is very straightforward. If we wanted to allocate an array of type char, assuming pstr is a pointer to char, we could write the following statement:

pstr = new char[20];  // Allocate a string of twenty characters

This allocates space for a char array of 20 characters and stores its address in pstr.
To remove the array that we have just created in the free store, we must use the delete operator. The statement would look like this:

delete [] pstr;          // Delete array pointed to by pstr

Note the use of square brackets to indicate that what we are deleting is an array. When removing arrays from the free store, you should always include the square brackets or the results will be unpredictable. Note also that you do not specify any dimensions here, simply [].

We can see how this works in practice by rewriting our program to calculate an arbitrary number of primes, but this time using memory in the free store to store them.

// Example1.cpp

// Calculating primes using dynamic memory allocation
#include <iostream>
#include <iomanip>
#include <cstdlib>           // For the exit function
using namespace std;
int main()
   long* pprime=0;           // Pointer to prime array
   long trial = 5;           // Candidate prime
   int count = 3;            // Count of primes found
   int found = 0;            // Indicates when a prime is found
   int max = 0;              // Number of primes required

   cout << endl
        << "Enter the number of primes you would like: ";
   cin >> max;               // Number of primes required
   if(!(pprime=new long[max]))
      cout << endl
           << "Memory allocation failed.";
      exit(1);               // Terminate program
   *pprime = 2;              // Insert three
   *(pprime+1) = 3;          // seed primes
   *(pprime+2) = 5;
      trial += 2;            // Next value for checking
      found = 0;             // Set found indicator
      for(int i = 0; i < count; i++)
                             // Division by existing primes
         found =(trial % *(pprime+i)) == 0; // True for exact division
         if(found)           // If division is exact
            break;           // it's not a prime
      if (found == 0)        // We got one... so save it in
         *(pprime+count++) = trial;         // primes array
   } while(count < max);
    // Output primes 5 to a line
   for(int i = 0; i < max; i++)
      if(i%5 == 0)      // New line on 1st, and every 5th line
         cout << endl;
      cout << setw(10) << *(pprime+i);
   delete [] pprime;             // Free up memory
   cout << endl;
   return 0;

How It Works

The out put of the programming will generate the prime numbers.

We have an extra #include statement for cstdlib, because we are using the function exit() if we run out of memory. After receiving the number of primes required in the int variable max, we allocate an array of that size in the free store using the operator new. We specify the size of the array required by putting the variable max between the square brackets following the array type specification. The pointer value, returned by new and stored in the pointer pprime, is validated in the if statement. If it turns out to be NULL, a message is displayed and the program is exited.

if(!(pprime=new long[max]))
   cout << endl
        << "Memory allocation failed.";
   exit(1);                   // Terminate program

Assuming that the memory allocation is successful, the first three array elements are set to the values of the first three primes.
We can't specify initial values for elements of an array allocated dynamically. We have to use explicit assignment statements if we want to set initial values for elements of the array.
The name of the pointer we have here, pprime. Equally, the output process is the same. Acquiring space dynamically is really not a problem at all. Once it has been allocated, it in no way affects how the computation is written.
Once we have finished with the array, we remove it from the free store using the delete operator, not forgetting to include the square brackets to indicate that it is an array we are deleting.

delete [] pprime;             // Free up memory

Dynamic Allocation of Multidimensional Arrays

Allocating memory in the free store for a multidimensional array involves using the operator new in only a slightly more complicated form than that for a one-dimensional array. Assuming that we have already declared the pointer pbeans appropriately, to obtain the space for our array beans[3][4] that we used earlier in this article, we could write this:

pbeans = new double [3][4];  // Allocate memory for a 3x4 array

Allocating space for a three-dimensional array simply requires the extra dimension specified with new, as in this example:

// Allocate memory for a 5x10x10 array
pBigArray = new double [5][10][10]; 

However many dimensions there are in the array that has been created, to destroy it and release the memory back to the free store, you write the following:

delete [] pBigArray;         // Release memory for array

You use just one pair of square brackets regardless of the dimensionality of the array with which you are dealing.
We have already seen that we can use a variable as the specification of the dimension of a one-dimensional array to be allocated by new. This extends to two or more dimensions only in that the leftmost dimension may be specified by a variable. All the other dimensions must be constants or constant expressions. So we could write this,

pBigArray = new double[max][10][10];

where max is a variable. However, specifying a variable for any other dimension will cause an error message to be generated by the compiler.