cómo crear una matriz 2d contigua en c ++?

Quiero crear una función que devuelva una matriz 2D contigua en C ++.

No es un problema crear la matriz con el comando:

int (*v)[cols] = new (int[rows][cols]); 

Sin embargo, no estoy seguro de cómo devolver esta matriz como un tipo general para una función. La función es:

  NOT_SURE_WHAT_TYPE create_array(int rows, int cols) { int (*v)[cols] = new (int[rows][cols]); return v; } 

Intenté doble * [] y doble ** y ninguno de los dos funciona. No me gustaría usar double *, ya que quiero acceder a esta matriz desde afuera como una matriz 2D.

Pregunta relacionada: ¿Cómo declaro una matriz 2d en C ++ usando new?

Si desea crear una matriz donde los datos son contiguos y no desea una matriz de 1 dimensión (es decir, desea usar la syntax [][] ), entonces debería funcionar lo siguiente. Crea una matriz de punteros y cada puntero apunta a una posición en un grupo de memoria.

 template  T** create2DArray(unsigned nrows, unsigned ncols, const T& val = T()) { T** ptr = new T*[nrows]; // allocate pointers T* pool = new T[nrows*ncols]{val}; // allocate pool for (unsigned i = 0; i < nrows; ++i, pool += ncols ) ptr[i] = pool; return ptr; } template  void delete2DArray(T** arr) { delete [] arr[0]; // remove the pool delete [] arr; // remove the pointers } int main() { double **dPtr = create2DArray(10,10); dPtr[0][0] = 10; // for example delete2DArray(dPtr); // free the memory } 

Tenga en cuenta que solo se realizan 2 asignaciones. También tenga en cuenta cómo desasignar la memoria. Puede mejorar el diseño convirtiéndolo en una verdadera clase en lugar de tener asignación / desasignación como 2 funciones separadas.

Editar: La clase no es similar a RAII, tal como dice el comentario. Lo dejo como un ejercicio para el lector. Una cosa que falta en el código anterior es la comprobación de que nRows y nCols son> 0 al crear dicha matriz.


Editar: para un ejemplo de matriz tridimensional de código similar al anterior, vea esta respuesta . Se incluye un código para retrotraer asignaciones si falla la asignación.

manejar recursos de memoria en bruto es a menudo repulsivo. La mejor opción es una envoltura simple como:

 struct array2D : private std::vector { typedef std::vector base_type; array2D() : base_type(), height_(0), width_(0) {} array2D(std::size_t h, std::size_t w) : base_type(h*w), height_(h), width_(w); int operator()(std::size_t i, std::size_t j) const { return base_type::operator[](i+j*height_); } int& operator()(std::size_t i, std::size_t j) { return base_type::operator[](i+j*height_); } std::size_t rows() const { return height_; } std::size_t cols() const { return width_; } private: std::size_t height_, width_; } 

la herencia privada le permite tomar todas las cosas buenas del vector, solo agregue su constructor 2D. La gestión de recursos es gratuita ya que el vector ctor / dtor hará su magia. Obviamente, el i + h * j se puede cambiar a cualquier orden de almacenamiento que desee.

vector > es 2D pero no será contiguo en la memoria.

Su función luego se convierte en:

 array2D create_array(int rows, int cols) { return array2D(cols,rows); } 

EDITAR:

También puede recuperar otras partes de la interfaz vectorial como begin / end o size con la cláusula usign para volver públicas las funciones privadas heredadas de los miembros.

A menos que se conozca el tamaño de las dos dimensiones en el momento de la comstackción, no tiene muchas opciones: asigne una sola rows*cols array de int s, y despliegue su propia indexación 2D con multiplicación y sum de enteros. Envolver esto en una clase puede producir una syntax agradable para acceder a los elementos de la matriz con el operador de corchetes cuadrados. Como su matriz es 2D, necesitará usar objetos proxy (también conocidos como “sustituto”) para el primer nivel de acceso a datos.

Aquí hay un pequeño código de muestra que usa std::vector para mantener una región de memoria contigua en la memoria dinámica:

 template class Array2D { vector data; size_t cols; public: // This is the surrogate object for the second-level indexing template  class Array2DIndexer { size_t offset; vector &data; public: Array2DIndexer(size_t o, vector &dt) : offset(o), data(dt) {} // Second-level indexing is done in this function T& operator[](size_t index) { return data[offset+index]; } }; Array2D(size_t r, size_t c) : data (r*c), cols(c) {} // First-level indexing is done in this function. Array2DIndexer operator[](size_t index) { return Array2DIndexer(index*cols, data); } }; 

Ahora puede usar Array2D como si fuera una matriz incorporada de C ++:

 Array2D a2d(10, 20); for (int r = 0 ; r != 10 ; r++) { for (int c = 0 ; c != 20 ; c++) { a2d[r][c] = r+2*c+1; } } 

Ejecutando demo en ideone .

Como estás usando C ++ y no C, te recomendaría usar un vector en lugar de jugar con new / delete.

Puede definir un bloque contiguo de memoria como este:

 std::vector my_matrix(rows*cols); 

Y ahora accede a este vector en una forma similar a 2d-array con la fórmula i * n + j, siendo i el índice de fila, j el índice de columna yn la longitud de una fila:

 my_matrix[i*n + j]; 

Es lo mismo que acceder a una matriz 2d con la matriz [i] [j]. Pero ahora tiene la ventaja de tener un bloque de memoria contiguo, no necesita preocuparse por lo nuevo / eliminar y puede compartir y devolver fácilmente este vector con funciones.

Ninguna de las formas de definir una matriz dinámica 2D en C ++ estándar es completamente satisfactoria en mi opinión.

Terminas teniendo que rodar tus propias soluciones. Afortunadamente ya hay una solución en Boost. boost :: multi_array :

 #include "boost/multi_array.hpp" template boost::multi_array create_array(int rows, int cols) { auto dims = boost::extents[rows][cols]; return boost::multi_array(dims); } int main() { auto array = create_array(4, 3); array[3][2] = 0; } 

Demostración en vivo