1

Not a duplicate of C++: multidimensional array initialization in constructor since the answers all appear to assume the bounds are known at compile-time.

I'm making a weighted undirected graph class arraygraph, backed by a 2D array of int, by the name of edges[][]. At instantiation time I don't really care what edges[][] holds; arraygraph has a method that reads a graph from a given filename and edges is set to a new int[n][n] (where n is the # of nodes in the file) by that function before it populates it.

Trouble is, g++ doesn't seem to like the way I've defined edges[][]. It wants to have set bounds for the array, and at compile time I don't know the bounds. Should I just redefine edges as an int *? Or as edges[][0]? Or something else entirely?

I'm not a C++ expert by any means (I'm a Python kinda guy) so complex, heavyweight options like the ones in Array with undefined size as Class-member are kinda out of scope (surely there's a simpler way than that...). If what I'm trying to do is a wrong thing entirely than that's also a useful thing to know, and it'd be handy to know what I ought to be doing instead.

Community
  • 1
  • 1
Schilcote
  • 2,344
  • 1
  • 17
  • 35
  • Does [this](http://stackoverflow.com/a/29055366/365496) answer your question? It only discusses two dimensional arrays, but it applies to any rectangular arrays (i.e., arrays where for each dimension, each element has the same size). – bames53 Mar 27 '15 at 22:18

2 Answers2

2

C++ doesn't know variable length arrays. So you need to define your array with a constant size. It's not possible either to redefine an array.

Two options for your multidimensional array:

  • dynamic array of arrays, implemented as int **edges
  • std::vector instead aka vector<vector<int>> edges;

vectors are extremely handy if you need to copy your data (done in a single statement), or change the sizes. So I'd recommend the second option :

int N=10; // dynamic! 
vector<vector<int>> m(N, vector<int>(N));

The alterative for using the pointer would be:

int N=10; // dynamic! 
int**m = new int*[N];    // allocate the first array 
for (int i = 0; i < N; i++) {  // allocate the second arrays
    m[i] = new int[N]{};
}

In both case, you'd access the data with the same syntax:

for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++)
        cout << m[i][j] << "\t";
    cout << endl;
}
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • `vector>` works but is generally not the best idea for rectangular arrays; it uses more memory and allocations than necessary. – bames53 Mar 27 '15 at 22:17
  • That's a step in the right direction, but is there any trick to adding values to those vectors? Does it just make a slot for me every time I write to a new index (I'll only be writing once and doing so from 1 to `n`, if that matters)? Or do I have to tell it "Redimension yourself to be this big" before I write to it? – Schilcote Mar 27 '15 at 22:20
  • 1
    @bames53 Life's short, DIMM's cheap. :P – Schilcote Mar 27 '15 at 22:22
  • 1
    Oh, and it'd be handy to know that I need to `#include ` to get a hold of `vector`. – Schilcote Mar 27 '15 at 22:28
  • @Schilcote It's not just using more memory; The fact that the memory is not contiguous also means it may be significantly slower. It's also more error prone and less readable, if you want rectangular arrays. – bames53 Mar 27 '15 at 22:30
  • The syntax in the demo above creates automatically all your N by N entries. You can resize() each vector as you want, later. Or you could just create a bigger vector as above and assign it to overwrite your old one. – Christophe Mar 27 '15 at 22:32
  • @bames if you use an `int**` you have no contiguity either. – Christophe Mar 27 '15 at 22:35
  • @Christophe That's true. I would not recommend `int**` either. Instead I'd suggest something along [these lines](http://stackoverflow.com/a/29055366/365496). – bames53 Mar 27 '15 at 22:46
  • @bames53 yes, flattening the array is also an alternative (+1 on the linked answer). But you'd need to explicitely to use the dimension in all indexing. And if code already exist for 2 dimensions, the OP would need to rewrite it. – Christophe Mar 27 '15 at 22:59
  • 1
    @Christophe It's not exactly trivial, but it's possible to implement a multi-dimensional matrix template class that supports an arbitrary number of dimensions, each of runtime size, and which uses a flattened array for storage: [proof of concept](https://gist.github.com/bames53/3d23426afbf47dc62514). This implementation uses some C++17 features but works with the current in-dev clang 3.7. – bames53 Mar 28 '15 at 01:46
  • @bames53 It's a very interesting idea ! – Christophe Mar 28 '15 at 08:51
0

It seems you are looking for sort of dynamic size array. Try using std::vector instead of the array.

warownia1
  • 2,771
  • 1
  • 22
  • 30