Search code examples
c++arrayspointer-to-pointer

Use of ptr-to-ptr array?


What is the use and explanation of something like this?:

int capacity;
int** number;
this->number = new int*[this->capacity];

I'm studying for an exam and in a test exam they put the requirement of using a pointer-to-pointer object and making a dynamic array from it. There are two classes; Wallet & WalletKeeper. In the solutions they did this in the header-file of WalletKeeper:

private:
    Wallet** wallets;
    int capacity;
    int size;
    /*other stuff below this*/

And in the constructor:

WalletKeeper::WalletKeeper(int capacity)
{
    this->capacity = capacity;
    this->size = 0;
    this->wallets = new Wallet*[this->capacity];
    this->initiate();
}

I understand a basic dynamic array like this:

Wallet * wallets = new Wallet[capacity];

This would mean you make a pointer which points to the place in the memory where this array of Wallets is made, so you can change the content of those memory slots. But why would you ever make a pointer to an array of pointers? What's the use?

Wallet has no array of its own, I would've understood it otherwise because I read this: The correct way to initialize a dynamic pointer to a multidimensional array?

Professors are on vacation until further ado.


Solution

  • The basic idea is that it allows you to create an "array of arrays". It has a narrow advantage over a matrix in that it allows you to have differently sized sub-arrays, but a disadvantage in that the memory of all objects is no longer contiguous across the entire array.

    Wallet ** w_ptr_ptr = new Wallet*[capacity];
    for(int i = 0; i < capacity; i++) {
        w_ptr_ptr[i] = new Wallet[i+1];
    }
    
    for(int i = 0; i < capacity; i++) {
        for(int j = 0; j < i+1; j++) {
            w_ptr_ptr[i][j] = Wallet(/*...*/);
        }
    }
    

    Note that in that code, w_ptr_ptr[0] has a differently sized array than w_ptr_ptr[1].

    As I alluded to in my comment though, your professor shouldn't be teaching like this. Because this code requires manual memory cleanup, and doesn't have any capacity to do automatic bounds checking, the code you should be using is:

    std::vector<std::vector<Wallet>> wallets;
    
    for(int i = 0; i < capacity; i++) {
        wallets.emplace_back(i+1); //Will automatically create a i+1-sized array.
    }
    
    for(int i = 0; i < wallets.size(); i++) { //Note I'm able to query the size here!
        for(int j = 0; j < wallets[i].size(); j++) { //Again I can query the size!
            wallets[i][j] = Wallet(/*...*/);
        }
    }