Pointers/Memory Allocation   «Prev  Next»
Lesson 13 Dynamic multidimensional arrays
Objective The allocate() function

Examine C++ array allocation function

The allocate() function in our dynamic, multidimensional array program is used for runtime array allocation.
void allocate(int r, int s, twod& m){
  m.base = new double*[s];
  assert (m.base);
  for (int i = 0; i < s; ++i){
     m.base[i] = new double[r];
     assert (m.base[i]);
  }  
  m.row_size = r;
  m.column_size = s;
}

  • allocate using new()
    The allocate() function uses new to allocate:
    1. a vector of column pointers, and
    2. a row of doubles

    First a column of pointers to double is allocated. Each of these pointers have the base address for a row of doubles. This space is allocated off the heap iteratively using a for loop. Notice the use of assert to test if the memory allocation was successful.

Expanded class in C++20

Here's an expanded class in C++20 that builds upon the given allocate function. This class provides additional functionality for a dynamic, multidimensional array.
#include <cassert>
#include <iostream>

class TwoDArray {
private:
    double** base;
    int row_size;
    int column_size;

public:
    // Constructor
    TwoDArray() : base(nullptr), row_size(0), column_size(0) {}

    // Destructor to free allocated memory
    ~TwoDArray() {
        deallocate();
    }

    // Allocate memory for the 2D array
    void allocate(int rows, int cols) {
        deallocate(); // Free any previously allocated memory
        base = new double*[cols];
        assert(base);
        for (int i = 0; i < cols; ++i) {
            base[i] = new double[rows];
            assert(base[i]);
        }
        row_size = rows;
        column_size = cols;
    }

    // Deallocate memory
    void deallocate() {
        if (base) {
            for (int i = 0; i < column_size; ++i) {
                delete[] base[i];
            }
            delete[] base;
            base = nullptr;
        }
        row_size = 0;
        column_size = 0;
    }

    // Get the number of rows
    int getRowSize() const {
        return row_size;
    }

    // Get the number of columns
    int getColumnSize() const {
        return column_size;
    }

    // Overload () operator for easy access to elements
    double& operator()(int row, int col) {
        assert(row >= 0 && row < row_size);
        assert(col >= 0 && col < column_size);
        return base[col][row];
    }

    // Const version of () operator
    const double& operator()(int row, int col) const {
        assert(row >= 0 && row < row_size);
        assert(col >= 0 && col < column_size);
        return base[col][row];
    }

    // Display the 2D array
    void print() const {
        for (int i = 0; i < row_size; ++i) {
            for (int j = 0; j < column_size; ++j) {
                std::cout << base[j][i] << " ";
            }
            std::cout << std::endl;
        }
    }
};
Example Usage:
C++
int main() {
    TwoDArray m;
    m.allocate(3, 3);

    // Initialize elements
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            m(i, j) = i * j;
        }
    }

    // Print the 2D array
    m.print();

    return 0;
}

This TwoDArray class provides the following functionality:
  1. Dynamic memory allocation and deallocation for a 2D array using allocate and deallocate methods.
  2. Boundary checking in the operator() overloads to ensure safe access to elements.
  3. Convenience methods to get the number of rows and columns (getRowSize and getColumnSize).
  4. A print method to display the contents of the 2D array.
  5. Protection against memory leaks through the use of a destructor.

Note that this implementation uses raw pointers and manual memory management for educational purposes. In a real-world scenario, consider using smart pointers or containers like std::vector for safer and more efficient memory management.

SEMrush Software