Well this is C++ so if you want a resizable 2D array, make a class for it.
Online demo : https://onlinegdb.com/tny4CbS6-C.
This class has the added benefit of keeping all data contiguous in memory (unlike a std::vector of std::vector which can put closely related data in different areas of memory).
And then you can easily have a resize method that will resize your instance.
Also note you probably do NOT want a global variable.
#include <vector>
#include <cstddef>
#include <stdexcept>
template <typename T>
class vector2D
{
public:
vector2D(std::size_t rows, std::size_t cols)
: m_data(rows * cols)
, m_rows(rows)
, m_cols(cols)
{
}
// Templated constructor from 2D C-style array
template <std::size_t N, std::size_t M>
vector2D(const T (&arr)[N][M])
: m_data(arr[0], arr[0] + N * M)
, m_rows(N)
, m_cols(M)
{
for (std::size_t i = 0; i < N; ++i)
{
m_data.insert(m_data.end(), arr[i], arr[i] + M);
}
}
// Resize to new dimensions, clearing all existing data
void resize(std::size_t rows, std::size_t cols)
{
std::vector<T>(rows * cols).swap(m_data);
m_rows = rows;
m_cols = cols;
}
// Non-const accessor
T& at(std::size_t row, std::size_t col)
{
if (row >= m_rows || col >= m_cols)
{
throw std::out_of_range("vector2D::at: index out of bounds");
}
return m_data.at(row * m_cols + col);
}
// Const accessor
const T& at(std::size_t row, std::size_t col) const
{
if (row >= m_rows || col >= m_cols)
{
throw std::out_of_range("vector2D::at: index out of bounds");
}
return m_data.at(row * m_cols + col);
}
// Unchecked accessor using operator()
T& operator()(std::size_t row, std::size_t col)
{
return m_data[row * m_cols + col];
}
// Unchecked const accessor using operator()
const T& operator()(std::size_t row, std::size_t col) const
{
return m_data[row * m_cols + col];
}
#if __cplusplus >= 202302L
T& operator[](std::size_t row, std::size_t col)
{
return m_data[row * m_cols + col];
}
// C++23 const multidimensional subscript operator
const T& operator[](std::size_t row, std::size_t col) const
{
return m_data[row * m_cols + col];
}
#endif
// Accessors for dimensions
std::size_t rows() const
{
return m_rows;
}
std::size_t cols() const
{
return m_cols;
}
// Direct access to underlying vector
std::vector<T>& data()
{
return m_data;
}
const std::vector<T>& data() const
{
return m_data;
}
private:
std::vector<T> m_data;
std::size_t m_rows;
std::size_t m_cols;
};
int main()
{
auto vec2d = vector2D<int>({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
auto val = vec2d[1,1];
vec2d.resize(2,2);
vec2d[1,1] = 1;
return val - vec2d[1,1];
}