tags:

views:

2001

answers:

8

how do i declare a two d array using new?

like for a "normal" array i would:

int* ary = new int[Size]

but

int** ary = new int[sizeY][sizeX]

a) deosn't work/compile and b) doesn't acomplish what:

int ary[sizeY][sizeX]

does.

+5  A: 

I recommend reading what C++ FAQ Lite says on the subject. Allocating (and more importantly, properly freeing) a multi-dimensional array using new can be tricky. Also, the next three FAQs in sequence from the one I linked are a good read. They'll give you tips on how to turn your array into its own class (enabling RAII, among other things), and an introduction to genericity using templates.

Kristo
+13  A: 

A dynamic 2D array is basically an array of pointers to arrays. You should initialize it using a loop:

int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
    ary[i] = new int[sizeY];
Mehrdad Afshari
Remember that anything allocated with `new` is created on the heap and must be de-allocated with `delete`, just keep this in mind and be sure to delete this memory from the heap when you're done with it to prevent leaks.
Kekoa
@kekoav: +1
Mehrdad Afshari
Also note that this one is an array of pointers. not of arrays. The pointer in turn point to arrays. Important to really correct on the terms, since many tutorials get it wrong too. An array of arrays would be contiguous, which this one is not
Johannes Schaub - litb
@litb: Is a[][] considered an "array of arrays" in spec or a multidimensional array?
Mehrdad Afshari
Yes, a T[][N] would be called "array of array [N] of T" and be an incomplete type, while T[][] would be an invalid type (all except the last dimensions must have a known size). T[N][M] is "array [N] of array[M] of T", while yours, T[sizeX] is "array [sizeX] of T" where T is a pointer to an int. Creating a dynamically 2d array works like this: new int[X][Y]. It will create an array of an allocated-type int[X][Y]. This is a "hole" in C++'s type system, since the ordinary type system of C++ doesn't have array dimensions with sizes not known at compile time, thus these are called "allocated types"
Johannes Schaub - litb
More to the point, "array of arrays" and "multidimensional array" is one and the same thing.
Johannes Schaub - litb
@litb: +1. great explanation of terminology.
Mehrdad Afshari
I've changed my mind on the type-system question though. I think "allocated type" doesn't mean to denote a completely different type category. I think it just says it's the type used for allocation. So, an array type can have a size not known at compile time, but you cannot declare an array with that type - instead you have to use `new`.
Johannes Schaub - litb
+2  A: 

Try doing this:

int **ary = new int[sizeY];
for (int i = 0; i < sizeY; i++)
    ary[i] = new int[sizeX];
stanigator
+9  A: 
int** ary = new int[sizeY][sizeX]

should be:

int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
    ary[i] = new int[sizeX];
}

and then clean up would be:

for(int i = 0; i < sizeY; ++i) {
    delete [] ary[i];
}
delete [] ary;

EDIT: as Dietrich Epp pointed out in the comments this is not exactly a light weight solution. An alternative approach would be to use one large block of memory:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]
Kevin Loney
+1 for showing the cleanup code too
Herms
It's a little heavier weight than it needs to be, and it allocates more blocks than you need. Multidimensional arrays only need one block of memory, they don't need one block per row. Allocating only one block makes cleanup simpler too.
Dietrich Epp
+14  A: 

Don't. Unless you have good reason, use std::vector<std::vector < int> > instead. Memory management will be far less error prone.

Edit: If you start to run into issues with the memory being non-contiguous, such as pointed out in the comments by Dietrich Epp, you could switch to using std::vector<int> and allocate (rows * columns) elements. You can then get a hold of the first element of this vector (&v[0]) and use the techniques in the other answers to treat it as a normal int[][]. However I would only do this if you actually profiled your code and saw that the non-contiguous memory was causing performance problems. It would likely only be an issue if you had a very large 2-D array. At least that is my guess. Again, profiling is the only real way to know.

The main point of my answer was to let vector do the memory management for you.

Brian Neal
i second that: after working months with geographical (2D) data.
ivanTheTerrible
Definitely, this is the way to go in real world apps unless you have an excuse.
Mehrdad Afshari
And speed isn't an excuse either. Vectors are just as fast as arrays under almost all circumstances, especially if you know the size in advance and pre-allocate it on construction, or using reserve().
Tyler McHenry
vector<vector<int> > is a little weird. In this case, vectors will NOT be as fast as arrays and allocation will certainly be much slower. If you allocate a 1024*1024 array this way, you will end up with making 1025 allocations instead of just one. You'll end up with more fragmentation, less locality of reference, and more overhead.
Dietrich Epp
@Dietrich Epp - vector will be just as fast as native arrays. The OP didn't specify his sizes, so it may be just fine for his use case. I agree that 1024 * 1024 might suffer some of the problems you described, but this would have to be profiled to see if it mattered for his application.
Brian Neal
I've taken some of Dietrich Epp's points into account and revised my answer slightly. Thanks Dietrich.
Brian Neal
+2  A: 

typedef is your friend

In C++ using new:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (array5k_t)[5000];

array5k_t *array5k = new array5k_t[5000];

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}

Or C style using calloc:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (*array5k_t)[5000];

array5k_t array5k = calloc(5000, sizeof(double)*5000);

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}
Robert S. Barnes
Accessing beyond the end of an array is not guaranteed to cause an error. If you're lucky, the program will just crash. You're definitely in the realm of undefined behavior.
Kristo
True, although the purpose of this example is really just to show how to use typedef and new together to declare a 2D array.
Robert S. Barnes
+3  A: 

I presume from your static array example that you want a rectangular array, and not a jagged one. You can use the following:

int *ary = new int[sizeX * sizeY];

Then you can access elements as:

ary[y*sizeX + x]

Don't forget to use delete[] on ary.

Dan Ellis
This is a good way to do it. You can also do vector<int> with size sizeX*sizeY for some nice extra safety.
Dietrich Epp
The best thing is to wrap this code in a class - you can perform a clean-up in destructor and you can implements methods get(x, y) and set(x,y, val) instead of forcing user to do multiplication by himself. Implementing operator[] is more tricky, but I believe it's possible.
Tadeusz Kopec
+2  A: 

This question was bugging me - it's a common enough problem that a good solution should already exist, something better than the vector of vectors or rolling your own array indexing.

When something ought to exist in C++ but doesn't, the first place to look is boost.org. There I found the Boost Multidimensional Array Library, multi_array. It even includes a multi_array_ref class that can be used to wrap your own one-dimensional array buffer.

Mark Ransom