1

I need to create a square matrix of a given size. I know how to create a dynamic one-dimensional array of a given size. Doesn't the same work for two dimensinal arrays like the lines below?

cin>>size;
int* a[][]=new int[size][size]
bames53
  • 86,085
  • 15
  • 179
  • 244
Amelie Malyan
  • 93
  • 1
  • 1
  • 8

3 Answers3

6
int* a[][]=new int[size][size]

No, this doesn't work.

main.cpp:4: error: only the first dimension of an allocated array may have dynamic size
    new int[size][size];
                  ^~~~

If the size of the rows were fixed then you could do:

// allocate an array with `size` rows and 10 columns
int (*array)[10] = new int[size][10];

In C++ you can't have raw arrays with two dimensions where both dimensions are dynamic. This is because raw array indexing works in terms of pointers; for example, in order to access the second row a pointer to the first needs to be incremented by the size of the row. But when the size of a row is dynamic the array doesn't know that size and so C++ doesn't know how to figure out how to do the pointer increment.

If you want an array with multiple dynamic dimensions, then you need to either structure the array allocations such that C++'s default array indexing logic can handle it (such as the top answers to this duplicate question), or you need to implement the logic for figuring out the appropriate pointer increments yourself.

For an array where each row has the same size I would recommend against using multiple allocations such as those answers suggest, or using a vector of vectors. Using a vector of vectors addresses the difficulty and dangerousness of doing the allocations by hand, but it still uses more memory than necessary and doesn't allow faster memory access patterns.

A different approach, flattening the multi-dimensional array, can make for code as easy to read and write as any other approach, doesn't use extra memory, and can perform much, much better.

A flattened array means you use just a single dimentional array that has the same number of elements as your desired 2D array, and you perform arithmetic for converting between the multi-dimensional indices and the corresponding single dimensional index. With new it looks like:

int *arr = new int[row_count * column_count];

Row i, column j in the 2d array corresponds to arr[column_count*i + j]. arr[n] corresponds to the element at row n/column_count and column n% column_count. For example, in an array with 10 columns, row 0 column 0 corresponds to arr[0]; row 0, column 1 correponds to arr[1]; row 1 column 0 correponds to arr[10]; row 1, column 1 corresponds to arr[11].


You should avoid doing manual memory management using raw new and delete, such as in the case of int *arr = new int[size];. Instead resource management should be wrapped up inside a RAII class. One example of a RAII class for managing dynamically allocated memory is std::vector.

std::vector<int> arr(row_count * column_count);
arr[column_count*i + j]

You can further wrap the logic for computing indices up in another class:

#include <vector>

class Array2d {
  std::vector<int> arr;
  int columns;
public:
  Array2d(int rows, int columns)
  : arr(rows * columns)
  , columns(columns)
  {}

  struct Array2dindex { int row; int column; };

  int &operator[] (Array2dindex i) {
    return arr[columns*i.row + i.column];
  }
};

#include <iostream>

int main() {
  int size;
  std::cin >> size;

  Array2d arr(size, size);

  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      arr[{i, j}] = 100;
    }
  }

  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      std::cout << arr[{i, j}] << ' ';
    }
    std::cout << '\n';
  }
}

Community
  • 1
  • 1
bames53
  • 86,085
  • 15
  • 179
  • 244
  • I'm getting a compile error ` error: expected expression arr[{i, j}] = 100; 2darray.cpp:29:11: error: expected ']' 2darray.cpp:29:10: note: to match this '[' arr[{i, j}] = 100; – Samyukta Ramnath Aug 21 '22 at 18:57
-1

If you're using C++11 you can also use std::array.

const int iRows = 3, iCols = 3; // number of rows and columns
std::array<std::array<int, iCols>, iRows> matrix;

// fill with 1,2,3  4,5,6  7,8,9
for(int i=0;i<iRows;++i)
    for(int j=0;j<iCols;++j)
        matrix[i][j] = i * iCols + j + 1;

This class also allows for bounds checking by using the function

std::array::at

which (just like operator[]) returns a const reference if the array-object is const-qualified or a reference if it is not. Please note that

std::array

is not a variable-sized array-type, like

std::vector
jensa
  • 2,792
  • 2
  • 21
  • 36
  • 2
    This one requires knowing the dimensions up front. It doesn't work if you don't know the dimensions until after user input. `cin >> size` in the example kills it. – Charlie Mar 14 '15 at 23:23
-2

You can use std::vector:

std::vector<std::vector<int*>> a(size, std::vector<int*>(size));

This will create a dynamically allocated 2D array of int* with width and height equal to size.

Or the same with new:

int*** a = new int**[size];
for (size_t i = 0; i < size; ++i)
    a[i] = new int*[size];
...
for (size_t i = 0; i < size; ++i)
    delete a[i];
delete a;

Note that there's no new[][] operator in C++, you just have to call new[] twice.

However, if you want to do it with new and delete instead of std::vector, you should use smart pointers instead of raw pointers, for example:

std::unique_ptr<std::unique_ptr<int*>[]> a(new std::unique_ptr<int*>[size]);
for (size_t i = 0; i < size; ++i)
    a[i].reset(new int*[size]);
...
// No need to call `delete`, std::unique_ptr does it automatically.
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • while using the method with "new" I get an error "int** a shadows a parameter". Any idea why this occurs? – Amelie Malyan Mar 14 '15 at 22:20
  • Maybe you have another variable called `a` somewhere? – Emil Laine Mar 14 '15 at 22:21
  • yes, you are right, I already had declared a before. So, in this case, do I need to write a=new int*[size] or **a=new int*[size]? – Amelie Malyan Mar 14 '15 at 22:28
  • I just get error in both cases, I don't know the reason – Amelie Malyan Mar 14 '15 at 22:29
  • `**a` just derefences `a` twice, that's not what you want. If you want to do `a = new int*[size]` then `a` has to be declared as `int**`. Btw check my edit on the smart pointer solution. – Emil Laine Mar 14 '15 at 22:32
  • Using a vector of vectors is not generally a good idea. If each row has its own independent size the such a structure is okay, but if every row has the same size then a vector of vectors will be slower and use more memory than a flattened 2d array. – bames53 Mar 14 '15 at 23:15
  • Probably not in the specific case of this person asking the question, but it may be important to some people looking for 2d arrays in C++. Also there's little reason to do premature pesimization here even if performance isn't that important; faster code can be just as clean and readable. – bames53 Mar 14 '15 at 23:21
  • True, but I'm pretty sure people serious about vector optimizations won't land on a -5 question about 2D array initialization syntax. – Emil Laine Mar 14 '15 at 23:24
  • Unfortunately the top voted answers to the [question that does come up](http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new) on a search have IMO even worse answers. – bames53 Mar 14 '15 at 23:43