C++/Dynamically allocate 2d array of pointers to objects
Expert: Joseph Moore - 7/23/2009
QuestionIt's been a long time since I've done any programming in C++ (been doing Java for the past several years), and I can't seem to figure out the answer to this problem.
I want to have a 2d array of pointers to user-defined objects. I want to dynamically allocate space for the array itself. I then want to allocate space for certain objects in the array.
In other words, let's say a user inputs 2 rows, 3 columns. I then want an array (called grid) that looks like
{ {NULL, NULL, NULL},
{NULL, NULL, NULL} };
Now the user wants to create a "Block" object at [0][1]. So grid[0][1] = new Block(); So now we have
{ {NULL, instantiatedBlockObj, NULL },
{NULL, NULL , NULL } };
I have been trying to figure out, and I know
Block** grid;
can be used to declare an array of pointers, but I don't know how to dynamically allocate space for the pointers without dynamically allocating space for all the objects.
For example, I tried
Block **grid;
grid = new Block*[rows];
But then I was able to call
grid[1]->method();
Without an error. I want grid[1] == NULL until I instantiate it.
And that's just a 1d array. I need the answer for a 2d array.
AnswerHi, Kevin.
In C++, the value of the allocated space is undefined until it is defined by you. So, if you want the data to be initialized to NULL, you will have to explicitly initialize it yourself using a memset or other operation. Your example is absolutely correct in its allocation, there is just no initialization of the values. You will want to do something like:
Block **grid;
grid = new Block*[rows];
memset(grid, 0, sizeof(Block*) * rows);
By doing this, you're initializing all of the pointers to NULL.
As for 2D array versus 1D array, if you want the memory to be contiguous, then you'll need to allocate a 1D array and use some math to treat it as a 2D array. Basically, when you allocate a 2D array on the stack in C++, it's no different than a 1D array except that you can index it differently. Consider the following:
int grid1[20];
int grid2[5][4];
In memory, these two arrays are laid out identically. It's a single, contiguous block of memory that holds 20 integers. The only difference between them is in the way that they can be indexed. You can, in fact, index both with row/column data, you just have to do a tiny bit of math for the 1D array:
for (int row = 0; row < numRows; ++row)
{
for (int col = 0; col < numCols; ++col)
{
grid1[row * numCols + col] = 0;
grid2[row][col] = 0;
}
}
In the above code, each one writes to the same offset each time. Using this method, you can treat a 1D array as if it were a 2D array.
If contiguous memory doesn't concern you, and you're OK with only the individual rows being contiguous, then you can use multiple new operations to generate a 2D array of pointers:
Block*** grid = new Block**[numRows];
for (int i = 0; i < numRows; ++i)
{
grid[i] = new Block*[numCols];
memset(grid[i], 0, sizeof(Block*) * numCols);
}
Using the above code, you have a single contiguous block of Block**'s, which you can consider your rows. Each Block** points to a single contiguous block of Block*'s, which you can consider your columns. The whole of the 2D array is not contiguous in memory, but the array of row pointers is contiguous, and each array of column pointers is contiguous.
OK, if I have left you confused about anything or if I've raised further questions, or even if you just have an unrelated question, feel free to let me know.