views:

4785

answers:

11

I went looking for this the other day, and thought it should probably be added to StackOverflow's reservoir of questions.

How would I go about dynamically allocating a multi-dimensional array?

+2  A: 

Here's the implementation I've got; I declare a single contiguous block of ints instead of creating new blocks inside my for loop, so I'm not causing page faults all over the place. Thanks to eJames for pointing out why this code was broken originally.

int width = 10, height = 10, totalSize = width*height;
int **myArray = new int*[width];
int *data = new int[totalSize];

for ( int i = 0; i < height; ++i )
{
    myArray[i] = data + (i*width);
}

// do some things here

delete[] data;
delete[] myArray;
eplawless
This code will not work as shown. Specifically, the writes to myArray[i] in your loop will be all over the place. See my modified loop here: http://stackoverflow.com/questions/340943/c-multi-dimensional-arrays-on-the-heap#341008
e.James
+6  A: 

If you know the size of nested dimensions already, you can also literally allocate a multi dimensional array using new:

typedef int dimensions[3][4];

dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;

instead of 10, a runtime determined value can be passed. Since it's not part of the type operator new returns, that's allowed. This is nice if you know the number of columns, but want to keep the number of rows variable, for example. The typedef makes it easier to read the code.

Johannes Schaub - litb
Not delete[][][] dim? ;-)
James Hopkin
this answer is kind of nasty: http://stackoverflow.com/questions/198051/why-delete-multidimensionalarray-operator-in-c-does-not-exist#326338 , but hopefully answers your concerns :)
Johannes Schaub - litb
Nice one, litb. I had no idea you could do that.
e.James
+1  A: 

Your loop would not write the pointer values into myArray properly. I would suggest the following instead:

int width = 10;
int height = 10;
int ** myArray = new int*[width];
int * data = new int[width*height];
int * index = data;
for (int i = 0; i < width; i++)
{
    myArray[i] = index;
    index += height;
}

// ...

delete[] data;
delete[] myArray;
e.James
You're right; I had this working, and refactored it without checking whether it works. Maybe I should stop breaking the build...
eplawless
+3  A: 

See this: C++ FAQ by Marshall Cline

See [16.16] and [16.17] sections

Naveen
I haven't thought about the C++ FAQ in some time. Along with Strostrup's book, it used to be one of my favorite programming reads.
Rich
FAQ [16.16] does not seem to be correct. It allocates memory for rows using new[]. Then sets each pointer to NULL and reallocates it. It never deallocates the memory that it set to NULL thus leaking that memory. Please check.
+2  A: 

std::vector<std::vector<int> > should be mentioned, as it's often the simplest way. However, be aware that it is non-rectangular. Not every std::vector<int> needs to have the same length.

MSalters
For a one-dimensional array it's simpler, but two dimensions complicates things. You have to explicitly initialize each element to the size you want it to be.
Mark Ransom
True, but that's not arduous: std::vector<std::vector<int> > myarray(height, std::vector<int>(width)); creates a rectangle full of 0s, indexed by [row][column]. Rows are contiguous in memory, columns are not.
Steve Jessop
+1  A: 
e.James
A: 

You can index a one dimensional as a 2, 3, or N dimensional one if you just space over the correct amount of elements. For example, if I've got 10 rows and 10 columns, I know that if I'm on row 3 I will have to go over at least 30 elements to get to it.

Somehow I prefer this notation for simple 2D arrays since I don't need to worry about nested levels of pointers. The downside is the messier index notation. Here's an example with a 2D array with n rows and m columns:

int *matrix = new int[n*m];

//set element (3,7) to 10
matrix[3*m+7] = 10;

//print the matrix
for (int i = 0; i < n; i++) {
  for (int j = 0; j < m; j++) {
    cout << matrix[i*m+j] << ' ';
  }
  cout << '\n';
}
Rich
+2  A: 

I'm surprised no one has mentioned boost::multi_array yet. I needed a 2D array in a program just last week, and found it to be a lot easier, and quicker to code, than the home-brewed solutions that I've come up with before (all of which are mentioned in other comments).

Head Geek
A: 

My question here covers mostly the same topic rather well thanks to some superb answers. However, it doesn't cover N-Dimensional arrays, which I haven't seen addressed in the answers here either, but that would be useful.

Tristan Havelick
+1  A: 

How about using Boost.Multiarray ? I believe it answers your need quite well ! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction

Here is an excerpt from the documentation page :

 #include < boost/multi_array.hpp >

 #include < cassert >

int main () 

{

  // Create a 3D array that is 3 x 4 x 2

  typedef boost::multi_array< double, 3 > array_type;

  typedef array_type::index index;

  array_type A(boost::extents[3][4][2]);


  // Assign values to the elements

  int values = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        A[i][j][k] = values++;

  // Verify values

  int verify = 0;

  for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j)

      for(index k = 0; k != 2; ++k)

        assert(A[i][j][k] == verify++);

  return 0;

}
Benoît
A: 

As another alternative, STLSoft includes a fixed_array_2d class (as well as 3D and 4D versions). Compared with the homebrewed solutions given here, it has a similar implementation but a more complete feature set (full support for iterators, etc.). Compared with boost::multi_array, it's lighter weight and easier on not-quite-compliant C++ compilers but (intentionally) lacks some of multi_array's features.

Josh Kelley