Jack Of Blades
Jack Of Blades

Reputation: 505

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.

Upvotes: 1

Views: 136

Answers (3)

BiagioF
BiagioF

Reputation: 9725

A pointer to pointers-objects is common used for matrices implementation. Indeed like pointers to objects implement dynamic array, as you've suggested in your question:

Wallet* wallets = new Wallet[capacity];

makes wallets points the first location of an array to num-capacity Wallet object.

[Wallet-obj] [Wallet-obj] [Wallet-obj] ... [Wallet-obj]
     0           1             2           capacity - 1

Pointer of pointers like:

Wallet** wallets = new Wallet*[capacity];

Create an array of Wallet pointer:

[Wallet-pointer] [Wallet-pointer] [Wallet-pointer] ... [Wallet-pointer]
        0              1                 2                capacity-1

Each pointer in the vector should point to an dynamic array.

I'll try to "draw" a representation:

 [0][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]
 [1][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]
 ...
 [capacity-1][wallet-pointer]  ----> [0][wallet obj] [1][wallet obj] ... [capacity-1][wallet obj]

So in order to access to an object you should use something like:

wallets[0][2];

That means access the 1-st pointer in the array of pointer, using the 1 "row" of object access to the 3-rd object of that row.

So as you can image, you have a matrix because you have a n-capacity dynamic array, like n-capacity rows.

Note

When you instantiate an array of pointers, you have to initialize each of them. This is a complete code:

Wallet** wallets = new Wallet*[capacity];

// Now for each pointer you have to allocate a dynamic array of n-elements.
for (size_t i = 0; i < capacity; ++i) {
  wallets[i] = new Wallet[capacity];
}

And the same is for deallocation phase:

// First of all, deallocate each object in each dynamic array:
for (size_t i = 0; i < capacity; ++i) {
  delete[] wallets[i];  // wallets[i] is a dynamic array to deallocate
}

// Finally deallocate the dynamic array of poiter
delete[] wallets;

Upvotes: 0

Xirema
Xirema

Reputation: 20396

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(/*...*/);
    }
}

Upvotes: 1

Sven Nilsson
Sven Nilsson

Reputation: 1879

There are many uses of arrays of pointers.

  1. Reordering. Suppose you want to reorder the objects in the array. Dealing with the pointers is much faster than moving the entire object.
  2. Dynamic allocation. You can delete or allocate each object individually.
  3. Reallocation and performance. Suppose you want to increase the size of the array. Reallocating the actual objects may lead to different types of problems (invalidation). Reallocating the array of pointers however is more or less trouble free and also much faster.

Upvotes: 3

Related Questions