Easy Tutorial
❮ Cpp Numbers C Function Strftime ❯

Dynamic Memory in C++

Understanding how dynamic memory works in C++ is essential for becoming a competent C++ programmer. Memory in a C++ program is divided into two parts:

Often, you cannot predict in advance how much memory you need to store specific information in a defined variable; the required memory size can only be determined at runtime.

In C++, you can use special operators to allocate memory on the heap for a given type of variable at runtime, which returns the address of the allocated space. This operator is the new operator.

If you no longer need the dynamically allocated memory space, you can use the delete operator to free the memory previously allocated by the new operator.

The new and delete Operators

Below is the general syntax for using the new operator to dynamically allocate memory for any data type:

new data-type;

Here, data-type can be any built-in data type including arrays, or any user-defined data type including classes or structures. Let's start with built-in data types. For example, we can define a pointer to a double type and request memory, which is allocated at execution time. We can accomplish this using the new operator as follows:

double* pvalue = NULL; // Initialize pointer to null
pvalue = new double;   // Request memory for the variable

If the free store is exhausted, memory allocation may fail. It is advisable to check if the new operator returns a NULL pointer and take appropriate action:

double* pvalue = NULL;
if (!(pvalue = new double))
{
   cout << "Error: out of memory." << endl;
   exit(1);
}

The malloc() function appeared in the C language and still exists in C++, but it is recommended to avoid using malloc() if possible. The main advantage of new over malloc() is that new not only allocates memory but also creates an object.

At any time, when you feel that a dynamically allocated variable is no longer needed, you can use the delete operator to free the memory it occupies, as shown below:

delete pvalue; // Free the memory pointed to by pvalue

The following example uses the above concepts to demonstrate how to use the new and delete operators:

Example

#include <iostream>
using namespace std;

int main ()
{
   double* pvalue = NULL; // Initialize pointer to null
   pvalue = new double;   // Request memory for the variable

   *pvalue = 29494.99;    // Store value at the allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // Free the memory

   return 0;
}

When the above code is compiled and executed, it produces the following result:

Value of pvalue : 29495

Dynamic Memory Allocation for Arrays

Suppose we want to allocate memory for a character array (a string of 20 characters). We can use the syntax from the example above to dynamically allocate memory for the array as follows:

char* pvalue = NULL;   // Initialize pointer to null
pvalue = new char[20]; // Request memory for the variable

To delete the array we just created, the statement is:

delete [] pvalue; // Delete the array pointed to by pvalue

Below is the general syntax for the new operator to allocate memory for multi-dimensional arrays:

One-Dimensional Array

// Dynamically allocate an array of length m
int *array = new int[m];

// Free the memory
delete [] array;

Two-Dimensional Array

int **array;
// Assume the first dimension length is m, the second dimension length is n
// Dynamically allocate space
array = new int*[m];
for (int i = 0; i < m; i++)
{
    array[i] = new int[n];
}
// Free the memory
for (int i = 0; i < m; i++)
{
    delete [] array[i];
}
delete [] array;

Example of a Two-Dimensional Array

#include <iostream>
using namespace std;

int main()
{
    int **array;
    int m = 3, n = 4;

    // Dynamically allocate space
    array = new int*[m];
    for (int i = 0; i < m; i++)
    {
        array[i] = new int[n];
    }

    // Free the memory
    for (int i = 0; i < m; i++)
    {
        delete [] array[i];
    }
    delete [] array;

    return 0;
}
int **p;
int i, j; // p[4][8]
// Start allocating a 4x8 two-dimensional array
p = new int *[4];
for (i = 0; i < 4; i++) {
    p[i] = new int[8];
}

for (i = 0; i < 4; i++) {
    for (j = 0; j < 8; j++) {
        p[i][j] = j * i;
    }
}
// Print data
for (i = 0; i < 4; i++) {
    for (j = 0; j < 8; j++) {
        if (j == 0) cout << endl;
        cout << p[i][j] << "\t";
    }
}
// Start freeing the allocated heap
for (i = 0; i < 4; i++) {
    delete[] p[i];
}
delete[] p;
return 0;
}

Three-dimensional array

int ***array;
// Assume the first dimension is m, the second dimension is n, the third dimension is h
// Dynamically allocate space
array = new int **[m];
for (int i = 0; i < m; i++) {
    array[i] = new int *[n];
    for (int j = 0; j < n; j++) {
        array[i][j] = new int[h];
    }
}
// Free
for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        delete[] array[i][j];
    }
    delete[] array[i];
}
delete[] array;

Three-dimensional array test example:

Example

#include <iostream>
using namespace std;

int main() {
    int i, j, k; // p[2][3][4]

    int ***p;
    p = new int **[2];
    for (i = 0; i < 2; i++) {
        p[i] = new int *[3];
        for (j = 0; j < 3; j++) {
            p[i][j] = new int[4];
        }
    }

    // Output p[i][j][k] three-dimensional data
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) {
            for (k = 0; k < 4; k++) {
                p[i][j][k] = i + j + k;
                cout << p[i][j][k] << " ";
            }
            cout << endl;
        }
        cout << endl;
    }

    // Free memory
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) {
            delete[] p[i][j];
        }
    }
    for (i = 0; i < 2; i++) {
        delete[] p[i];
    }
    delete[] p;
    return 0;
}

Dynamic memory allocation for objects

Objects are no different from simple data types. For example, consider the following code where we use an array of objects to clarify this concept:

Example

#include <iostream>
using namespace std;

class Box {
   public:
      Box() {
         cout << "Constructor called!" << endl;
      }
      ~Box() {
         cout << "Destructor called!" << endl;
      }
};

int main() {
   Box* myBoxArray = new Box[4];

   delete[] myBoxArray; // Delete array
   return 0;
}

If you want to allocate memory for an array containing four Box objects, the constructor will be called 4 times. Similarly, when these objects are deleted, the destructor will also be called the same number of times (4 times).

When the above code is compiled and executed, it produces the following result:

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
❮ Cpp Numbers C Function Strftime ❯