As other answers have said: allocate n * m
entries to create the contiguous data, and then it can be wrapped in pointers to create a 2d array.
... absolutely requires use of arrays and NOT vectors ...
I'm not sure if vector
is a constraint based on the API being used, or requirements -- but it's worth noting that vector
can be used for the memory management of the implementation -- while still using the raw data (which can be accessed by &vec[0]
or vec.data()
, which returns a pointer to the first element of the array, and can be used with functions accepting raw pointers).
Since this question is about c++, one option is to wrap an array of n * m
in a class
that acts like a 2-d array while actually being contiguous.
A simple example could be:
class array_2d
{
public:
array_2d( std::size_t rows, std::size_t columns )
: m_rows(rows), m_cols(columns), m_array( new char[rows * columns] )
{
}
~array_2d()
{
delete [] m_array;
}
// row-major vs column-major is up to your implementation
T& operator()( std::ptrdiff_t row, std::ptrdiff_t col )
{
// optional: do bounds checking, throw std::out_of_range first
return m_array[row * m_cols + col];
// alternatively:
// return m_array[col * m_rows + row];
}
// get pointer to the array (for raw calls)
char* data()
{
return m_array;
}
private:
char* m_array;
std::size_t m_rows;
std::size_t m_cols;
};
(Ideally char*
would be std::unique_ptr<char[]>
or std::vector<char>
to avoid memory-leak conditions, but since you said vector
is not viable, I'm writing this minimally)
This example overloads the call operator (operator()
) -- but this could also be a named function like at(...)
; the choice would be up to you. The use of such type would then be:
auto array = array_2d(5,5); // create 5x5 array
auto& i01 = array(0,1); // access row 0, column 1
Optionally, if the [][]
syntax is important to behave like a 2d-array (rather than the (r,c)
syntax), you can return a proxy type from a call to an overloaded operator []
(untested):
class array_2d_proxy
{
public:
array_2d_proxy( char* p ) : m_entry(p){}
char& operator[]( std::ptrdiff_t col ){ return m_entry[col]; }
private:
char* m_entry;
};
class array_2d
{
...
array_2d_proxy operator[]( std::ptrdiff_t row )
{
return array_2d_proxy( m_array + (row * m_cols) );
}
...
};
This would allow you to have the 'normal' 2d-array syntax, while still being contiguous:
auto& i00 = array[0][0];