0

I'd like to dynamically allocate and then deallocate a 2D array using pointers. My idea is to create a pointer to an array of pointers, where each pointer points to an int and that's how I would like to do it. The functions are type of bool as I want to return a boolean whether the action was successful or not.

The problem is that deallocateTwoDimTable function doesn't return a bool, so it seems like it doesn't work at all. If I don't use int** table = nullptr; but leave it uninitialised int** table, then I get the error (when deallocating) that the memory that I want to free haven't been initialised.

The code does work if I change the parameter int **table to int **&table, but I guess that means passing by reference instead of using pointers. How do I make it work? All the help is really appreciated :)

Here's my main method:

int main() {
    int** table = nullptr;
        
    int sizeX = 5; // rows
    int sizeY = 3; // columns
    
    bool allocationResult = allocateTwoDimTable(table, sizeX, sizeY);
    cout << endl << "allocation result: " << (allocationResult ? "true" : "false") << endl;
    
    bool deallocationResult = deallocateTwoDimTable(table, sizeX);
    cout << endl << "deallocation result: " << (deallocationResult ? "true" : "false");
}

Allocation function:

bool allocateTwoDimTable(int **table, int sizeX, int sizeY) {
    if (sizeX <= 0 || sizeY <= 0) return false;

    // allocate 2D table
    table = new int*[sizeX];
    for(int i = 0; i < sizeX; i++) {
        table[i] = new int[sizeY];
    }

    cout << endl << "Table " << sizeX << " x " << sizeY << endl;
    for(int i = 0; i < sizeX; i++) {
        cout << endl;
        for(int j = 0; j < sizeY; j++) {
            cout << table[i][j] << ", ";
        }
    }

    return true;
}

Deallocation function:

bool deallocateTwoDimTable(int **table, int sizeX) {
    if(sizeX <= 0) return false;

    for (int k = 0; k < sizeX; k++) {
        delete[] table[k];
    }

    delete[] table;

    return true;
}
kabugh
  • 305
  • 1
  • 9
  • 30
  • 1
    If you are setting `table` in the function like `table = new int*[sizeX];`, you have to pass it by reference, otherwise you would just set a copy, which is lost after the function ends. – mch Oct 14 '20 at 13:36
  • 1
    the best way to allocate memory for something like an array is to use `std::vector`. they are more secure when it comes to destroy the vector, in fact if you allocate memory yourself you also should be make sure to deallocate the memory yourself before destroying the pointer. you can use the function `push_back` from `std::vector`. – gibs Oct 14 '20 at 13:39
  • 1
    Your `table` array's elements are not initialized. You may not try to read from its elements (for example with `cout << table[i][j]`) until you have assigned a value to those elements. – François Andrieux Oct 14 '20 at 13:41
  • 1
    [A complete example](https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048). In addition, read the comments on why your method, even if you get it to work, has flaws. – PaulMcKenzie Oct 14 '20 at 13:42
  • 1
    *"but I guess that means passing by reference instead of using pointers"* That would still be using pointers, even if they are passed by reference. It is simply a reference to a pointer. – François Andrieux Oct 14 '20 at 13:43

3 Answers3

1

You have to pass the pointer by reference. Otherwise the function allocateTwoDimTable will deal with a copy of the value of the original pointer. That is changing the copy will not influence on the original pointer.

Also the parameters sizeX and sizeY should have the type size_t because in general the type int can be unable to specify required dimensions of arrays.

The function can be declared like

bool allocateTwoDimTable( int ** &table, size_t sizeX, size_t sizeY);

Pay attention to that you are created uninitialized arrays

table[i] = new int[sizeY]

So outputting them

cout << table[i][j] << ", ";

invokes undefined behavior.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks for your detailed answer. And is there any alternative way to deal with this without reference? I mentioned that it definitely does work when using the reference, but I was wondering whether I could do it in any other way. – kabugh Oct 14 '20 at 13:53
  • 1
    @kabugh In the main comments, I linked to an answer that shows how it is done using just pointers. – PaulMcKenzie Oct 14 '20 at 13:57
  • 1
    @kabugh You could return a pointer to teh created array of pointers instead of the type bool. In this case you could just check whether a pointer is equal to nullptr. Take into account that you will need to use the operator new that does not through an exception. – Vlad from Moscow Oct 14 '20 at 13:58
1

When you need to pass reference or by pointer, when given the opportunity, it's better to pass by reference.

A pointer can take null arguments, a reference can't, it's safer to use, unless, for some reason, you specifically need to pass null arguments which I believe is not the case.

Note that you're accessing uninitialized memory when you print the array.

Also note that despite using boolean flag to signal allocation errors you're code still is vulnerable, a better way to do this would be to use std::exception.

bool allocateTwoDimTable(int** &table, int sizeX, int sizeY) {
    if (sizeX <= 0 || sizeY <= 0) return false;

    // allocate 2D table
    table = new int* [sizeX];
    
    for (int i = 0; i < sizeX; i++) {
        table[i] = new int[sizeY];
    }

    cout << endl << "Table " << sizeX << " x " << sizeY << endl;
    for (int i = 0; i < sizeX; i++) {
        cout << endl;
        for (int j = 0; j < sizeY; j++) {
            table[i][j] = i + j; //initializing elements of the array
            cout << table[i][j] << ", ";
        }
    }

    return true;
}
bool deallocateTwoDimTable(int (** &table), int sizeX) {
    if (sizeX <= 0) return false;

    for (int k = 0; k < sizeX; k++) {
        delete[] table[k];
    }

    delete[] table;

    return true;
}
int main() {

    int** table = nullptr;

    const int sizeX = 5; // rows
    const int sizeY = 3; // columns

    try {    
        const bool allocationResult = allocateTwoDimTable(table, sizeX, sizeY);
        cout << endl << "allocation result: " << (allocationResult ? "true" : "false") << endl;

        const bool deallocationResult = deallocateTwoDimTable(table, sizeX);
        cout << endl << "deallocation result: " << (deallocationResult ? "true" : "false");
    }
    catch (std::exception& e)
    {
        std::cout << e.what();
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
anastaciu
  • 23,467
  • 7
  • 28
  • 53
1

have a look at this answer https://stackoverflow.com/a/936709/9936992 they are also mentioning the possibility to use a single array that will mimic the two D array