24

I've tried looking but I haven't found anything with a definitive answer. I know my problem can't be that hard. Maybe it's just that I'm tired..

Basically, I want to declare a pointer to a 2 dimensional array. I want to do it this way because eventually I will have to resize the array. I have done the following successfully with a 1D array:

int* array;
array = new int[somelength];

I would like to do the following with a 2D array but it won't compile:

int* array;
array = new int[someheight][somewidth];

The compiler gives me an error stating that ‘somewidth’ cannot appear in a constant-expression. I've tried all sorts of combinations of ** and [][] but none of them seem to work. I know this isn't that complicated...Any help is appreciated.

M.M
  • 130,300
  • 18
  • 171
  • 314
vince88
  • 3,219
  • 5
  • 22
  • 26

6 Answers6

46
const int someheight = 3;
const int somewidth = 5;

int (*array)[somewidth] = new int[someheight][somewidth];
luca
  • 5,100
  • 7
  • 34
  • 48
Tony The Lion
  • 57,181
  • 57
  • 223
  • 390
  • 9
    Unlike the other answers here, this one actually answers the question, which was how to declare a pointer to a multidimensional array - not a jagged array. This is an important differentiation for performance-sensitive applications. It works if "somewidth" is a constant, and only the "someheight" changes. If you look at how this 2D array is laid out in memory - it's all together and contiguous, with no more than the single "new" memory allocation done. The answer by Alexander Rafferty is also good if the width is also dynamic. The other answers are slow because they do a ton of mallocs... – James Johnston Jan 14 '14 at 16:03
  • 1
    How do you properly destroy this array? delete[] array; I assume so since it's really a contiguous piece of memory. – Dicer Mar 01 '19 at 21:53
  • Just to clarify James Johnston's important note. Arrays and pointers are not the same: an array can decay into a pointer, but a pointer doesn't carry state about the size/configuration of the data to which it points. This prevents using pointers of pointers as a contiguous memory. Still the decay of an N dimensional array to a pointer to N-1 dimensional array is allowed by c++ since you can lose the leftmost dimension and still being able to correctly access array elements with N-1 dimension information. Details in https://stackoverflow.com/a/3925968/1201614 – luca Apr 04 '20 at 17:37
14

I just found this ancient answer still gets read, which is a shame since it's wrong. Look at the answer below with all the votes instead.


Read up on pointer syntax, you need an array of arrays. Which is the same thing as a pointer to a pointer.

int width = 5;
int height = 5;
int** arr = new int*[width];
for(int i = 0; i < width; ++i)
   arr[i] = new int[height];
Community
  • 1
  • 1
dutt
  • 7,007
  • 10
  • 46
  • 76
  • 2
    Did you try this? It doesn't compile (if height and width are both variables) – The Archetypal Paul Oct 11 '10 at 07:32
  • Yes I have tried this and still get the same error with the compiler. it will say that "‘width’ cannot appear in a constant-expression" – vince88 Oct 11 '10 at 07:32
  • 1
    If I were to access an element of this array would it just be arr[width][height]? – vince88 Oct 11 '10 at 07:47
  • Awesome. Thanks for the help. – vince88 Oct 11 '10 at 07:54
  • It is very well specified that when declaring a 2D-Array the row argument can be a variable , but the column argument has to be constant only. – Krishna Oza Nov 26 '14 at 04:37
  • 3
    No, array of array and array of pointers are not the same thing. Why is this post accepted ? The answer of Tony The Lion is the correct one, this one is *completely* wrong. – Bregalad Mar 23 '15 at 15:10
6

A ready to use example from here, after few seconds of googling with phrase "two dimensional dynamic array":

int **dynamicArray = 0;

// memory allocated for elements of rows. 
dynamicArray = new int *[ROWS];

// memory allocated for  elements of each column.  
for( int i = 0 ; i < ROWS ; i++ ) {
    dynamicArray[i] = new int[COLUMNS];
}

// free the allocated memory 
for( int i = 0 ; i < ROWS ; i++ ) {
    delete [] dynamicArray[i];
}
delete [] dynamicArray;
Arun
  • 18,092
  • 8
  • 46
  • 58
  • 2
    This is an array of arrays, not really a 2D one. – Alexander Rafferty Oct 11 '10 at 07:38
  • 3
    @Alexander Rafferty: I see -- what is the difference between "array of arrays" and "2D arrays'? – Arun Oct 11 '10 at 07:45
  • 6
    @ArunSaha, this is old, but to answer your question and for anyone else that stumbles across this, a 2-D array is contiguous in memory; a dynamic array of dynamic arrays is contiguous in the first dimension, but each array in the second dimension is stored separately – Stephen Lin Mar 14 '13 at 03:08
  • @Stephen Lin: Appreciate your explanation! Say there is a also `int staticArray[ ROWS ][ COLUMNS ];`. Also assume that there is a function `printArray( int arr[ ROWS ][ COLUMNS ] )` which access and prints all the elements as `arr[ i ][ j ]`. One could pass either `staticArray` or `dynamicArray` to that function and it would work, correct? There is structural difference and your point is valid. However, since there is no behavioral difference, I tend to consider the difference as a implementation detail. – Arun Mar 14 '13 at 22:49
  • @ArunSaha, no that's the point, you can pass `int[N]` (array of `N` integers) as `int *` (pointer to integer) but you can't pass `int[R][C]` (array of R of array of C integers) as an `int **` (pointer to pointer to integer); there is no implicit conversion and if you cast it to make it work you'll corrupt memory; `int [R][C]` decays to `int (*)[C]` (pointer to array of `C` integers) instead...see [this answer](http://stackoverflow.com/questions/3920729/in-c-c-is-char-arrayname-a-pointer-to-a-pointer-to-a-pointer-or-a-pointe?rq=1) – Stephen Lin Mar 14 '13 at 22:54
  • @ArunSaha just think about how element `staticArray[x][y]` would be accessed versus `dynamicArray[x][y]` by the compiler...the first is `*(&staticArray[0][0] + (x * C + y))` but the second is `*(*(&dynamicArray[0] + x) + y)`; not equivalent at all – Stephen Lin Mar 14 '13 at 23:01
  • @Stephen Lin: I agreed and admitted that there indeed is structural difference, the memory layout is certainly different. The point I am trying to convey is that, from a client's (e.g. `printArray()`), there is no difference. (In other words, the difference is abstracted out). Agree or disagree? [I consider the situation similar to when I create a `Array2d` class, and provide a member function `getElement( int i, int j)`, the user is not expected to know how `getElement()` is implemented.] – Arun Mar 15 '13 at 16:56
  • @ArunSaha what I'm saying is the difference is not abstracted out, the types are not equivalent and passing a dynamic array `int**` as `int[R][C]` will not work. – Stephen Lin Mar 15 '13 at 18:20
6

I suggest using a far simpler method than an array of arrays:

#define WIDTH 3
#define HEIGHT 4

int* array = new int[WIDTH*HEIGHT];
int x=1, y=2, cell;
cell = array[x+WIDTH*y];

I think this is a better approach than an array of an array, as there is far less allocation. You could even write a helper macro:

#define INDEX(x,y) ((x)+(WIDTH*(y)))

int cell = array[INDEX(2,3)];
Alexander Rafferty
  • 5,933
  • 2
  • 29
  • 55
2

Personally, my preference is to use a syntactic trick to declare a pointer to the dynamically sized multi-dimensional array. This works in compilers that support Variable Length Arrays (VLAs), which all C++ compilers should, and most current C compilers.

The basic idea is captured in this:

void bar (int *p, int nz, int ny, int nx) {
  int (*A)[ny][nx] = (int(*)[ny][nx]) p;

"p" points at the (contiguous) block of space you want to treat as a multi-dimensional array. "A" has the same value as "p", but the declaration makes the compiler treat references to "A" in the multi-dimensional way you want. For example:

#include <iostream>
using namespace std;

void bar (int *p, int nz, int ny, int nx)
{
  int (*A)[ny][nx] = (int(*)[ny][nx]) p;

  for (int ii = 0; ii < nz; ii++) {
    for (int jj = 0; jj < ny; jj++) {
      for(int kk = 0; kk < nx; kk++) {
          A[ii][jj][kk] = ii*1000000 + jj*1000 + kk;
      }
    }
  }
}


void out (int *p, int nz, int ny, int nx)
{
  int (*A)[ny][nx] = (int(*)[ny][nx]) p;
  cout << A[11][22][33] << endl;
}


int main (void)
{
  int NX = 97;
  int NY = 92;
  int NZ = 20;
  int *space = new int [NZ * NY * NX];

  bar (space, NZ, NY, NX);
  out (space, NZ, NY, NX);
  return 0;
}

Running this produces the output "11022033"

The declaration of the "A" alias is a little weird looking, but it allows you to directly and simply use the desired multi-dimensional array syntax

1

I think this will do

int r, c ;
std::cin>>r>>c ;
int *array = new int[r*c] ; 

You can input the values by doing something like this

for (int i = 0 ; i < r ; i++){
    for (int j = 0 ; j < c ; j++){
        std::cin>>array[i *c + j] ; 
    }
}
Tasdik Rahman
  • 1,750
  • 1
  • 19
  • 36