Declaring Multidimensional Array of Unknown Size

Hello,

So I have a header file for a class where I want to privately declare a 2D array of an object type Piece (with undefined # rows and columns until user tells us) and then a constructor in the class I laid out in the header where I am supposed to initialize the type with two ints as sizes.

Incorrectly (I have a java background and I'm spit-balling), I want to do this:

1
2
3
4
5
6
7
8
9
10
11
12
class Class {
private:
  int rows;
  int cols;
  Piece square[][]; // Declare a 2D array in Class.h
}
  

/* Initialize square[][] in Class.cpp with size rows and cols that will be filled in by user at main*/
Piece::Piece(int rows, int cols) {
  square = new Piece[rows][cols]; 
}


Thanks for your help.

*Edit: Typo
Last edited on
You can use std::vectors for this. A "vector of vectors" is equivalent to an "array of arrays", which is what a 2D array essentially is.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>

class Piece { 
	
};

class Class {
  
public:
  Class(int rows, int cols)
  : rows(rows), cols(cols),
    square(rows, std::vector<Piece>(cols))
  {
    
  }
  
public: // making public for purposes of demonstration
  int rows;
  int cols;
  std::vector<std::vector<Piece>> square; // Declare a 2D array in Class.h
};
  
  
int main()
{
  int rows  =3;
  int cols = 2;
  Class myClass(rows, cols);
  Piece myPiece;
	
  myClass.square[1][1] = myPiece;
  
  // re-assign it, just for demonstration:
  myClass.square = std::vector<std::vector<Piece>>(rows, std::vector<Piece>(cols));

}
Last edited on
Thank you for such a thorough explanation! I was wondering if there was also a way to do this maybe with pointers or something if we declared square as a pointer or pointer to a pointer? I wonder if there is a way to do this without the vector library? Again, thank you for clarifying.
yes, you can do it with pointers.

int ** twod;
twod = new int*[rows];
for(i = 0; i < rows; i++)
twod[i] = new int[cols];

and delete from the inside out.
for(i = 0; i < rows; i++)
delete[] twod[i];
delete [] twod;

its often much better to just do 1-d and access as-if 2d:
int * twod[rows*cols];
twod[which_col+ cols*whichrow];
//now you can transpose in place without a do-over, you can memcpy it, you can memset it, delete and new are simpler, its less prone to page faults for small/medium data and many other perks that ** approach do not allow.

it is highly recommended you avoid pointers, but that is how you would do it.

many of the perks of the 1-d approach carry into vectors. nested vectors have some of the problems ** does.

vector is part of the c++ language, like cout. Its not a 3rd party library or language extension.
Last edited on
Thanks for your help! It's interesting to see the two different approaches. I am very new to this, by "delete from the inside out" do you mean something like a destructor? Thanks.
Last edited on
But wait, there’s more! Along with vectors and pointers, you get the matrix class, for free!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef MATRIX_HPP
#define MATRIX_HPP

#include <algorithm>
#include <vector>

template <typename T>
struct matrix
{
  typedef std::size_t     Index;
  typedef std::vector <T> Data;

  Index rows;
  Index columns;
  Data  data;

  matrix(): rows(), columns() { }
  matrix( Index rows, Index columns ): rows(rows), columns(columns), data( rows * columns, T() ) { }

  Index index( Index row = 0, Index column = 0 ) const { return row * columns + column; }

  T&       operator () ( Index row, Index column )       { return data[index( row, column )]; }
  const T& operator () ( Index row, Index column ) const { return data[index( row, column )]; }

  void resize( Index rows, Index columns )
  {
    matrix m( rows, columns );
    for (Index row = 0; row < std::min( rows,    this->rows    ); ++row)
    for (Index col = 0; col < std::min( columns, this->columns ); ++col)
      m( row, col ) = operator () ( row, col );
    data.swap( m.data );
    this->rows    = rows;
    this->columns = columns;
  }

  void clear()
  {
    rows = columns = 0;
    data.clear();
  }
};

#endif 

Enjoy!
I am very new to this, by "delete from the inside out" do you mean something like a destructor? Thanks.

No, destructors are automatic. (but the vast majority of explicit dtors are likely calling a delete statement).

Pointers work like this:
you ask the operating system for memory.
you use the memory.
you give the memory back when done.
for nested memory access (pointer to pointer to memory) you have to release it from the inside out (pointer to object destroyed before pointer to pointer memory block).

my example shows this: the delete statement gives the memory back to the OS. While all major/computer sized/modern operating systems clean up if the program ends, not giving the memory back explicitly is bad practice and it will make large projects have all sorts of problems. Every single new statement must be paired to a delete. Vectors handle this for you, which is one reason they are preferred. Pointers are generally avoided if not necessary, and for just data storage, they are not necessary.
Last edited on
Thank you very much! That makes sense. Also, I will definitely look through the matrix class, also. Thanks for your help, guys.
Topic archived. No new replies allowed.