2008-12-04 17 views

Respuesta

24

Si se conoce el tamaño de las dimensiones anidadas ya, también puede asignar literalmente una matriz multidimensional utilizando nueva:

typedef int dimensions[3][4]; 

dimensions * dim = new dimensions[10]; 
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42; 
delete [] dim; 

en lugar de 10, un valor determinado de tiempo de ejecución se puede pasar. Como no es parte del operador nuevo, está permitido. Esto es bueno si conoce el número de columnas, pero desea mantener la cantidad de filas variables, por ejemplo. El typedef hace que sea más fácil leer el código.

+0

No borrar [] [] [] dim? ;-) –

+3

esta respuesta es desagradable: http://stackoverflow.com/questions/198051/why-delete-multidimensionalarray-operator-in-c-does-not-exist#326338, pero espero que responda a sus inquietudes :) –

+0

Nice one, litb. No tenía idea de que pudieras hacer eso. –

3

Aquí está la implementación que tengo; Declaro un solo bloque contiguo de int s en lugar de crear nuevos bloques dentro de mi ciclo for, así que no estoy causando fallas en las páginas por todos lados. Gracias a eJames por señalar por qué este código se rompió originalmente.

int width = 10, height = 10, totalSize = width*height; 
int **myArray = new int*[width]; 
int *data = new int[totalSize]; 

for (int i = 0; i < height; ++i) 
{ 
    myArray[i] = data + (i*width); 
} 

// do some things here 

delete[] data; 
delete[] myArray; 
+0

Este código no funcionará como se muestra. Específicamente, las escrituras en myArray [i] en su ciclo estarán por todos lados. Ver mi bucle modificado aquí: http://stackoverflow.com/questions/340943/c-multi-dimensional-arrays-on-the-heap#341008 –

2

Su bucle no escribiría correctamente los valores del puntero en myArray. Yo sugeriría que el siguiente en su lugar:

int width = 10; 
int height = 10; 
int ** myArray = new int*[width]; 
int * data = new int[width*height]; 
int * index = data; 
for (int i = 0; i < width; i++) 
{ 
    myArray[i] = index; 
    index += height; 
} 

// ... 

delete[] data; 
delete[] myArray;
+0

Tienes razón; Lo hice funcionar y lo refactoré sin verificar si funciona. Tal vez debería dejar de romper la compilación ... – eplawless

6

ver esto: "¿Cómo asigno matrices multidimensionales utilizando las nuevas" C++ FAQ by Marshall Cline

Ver y "¡Pero el código de las preguntas frecuentes anterior es muy complicado y propenso a errores! ¿No hay una manera más simple?" secciones

+0

No he pensado en las preguntas frecuentes sobre C++ en algún momento. Junto con el libro de Strostrup, solía ser una de mis lecturas de programación favoritas. – Rich

+0

Preguntas frecuentes [16.16] no parece ser correcto. Asigna memoria para filas usando new []. Luego establece cada puntero a NULL y lo reasigna. Nunca desasigna la memoria que establece en NULL y, por lo tanto, pierde esa memoria. Por favor, compruebe. – user236215

3

std::vector<std::vector<int> > se debe mencionar, ya que a menudo es la forma más sencilla. Sin embargo, tenga en cuenta que no es rectangular. No todos los std::vector<int> deben tener la misma longitud.

+0

Para una matriz unidimensional es más simple, pero dos dimensiones complican las cosas. Debe inicializar explícitamente cada elemento al tamaño que desea que sea. –

+0

Es cierto, pero eso no es arduo: std :: vector > myarray (height, std :: vector (width)); crea un rectángulo lleno de 0, indexado por [fila] [columna]. Las filas son contiguas en la memoria, las columnas no. –

6

Para completar, aquí hay una mejor manera de hacerlo en C++ cuando conoces los límites de la matriz antes de tiempo. El beneficio de utilizar la siguiente clase es que no tiene que preocuparse por llamar a delete [] en sus datos. Esto significa que esta clase será a prueba de excepciones, y todas las otras cosas geniales sobre RAII.

template<typename T, int width, int height> 
class MultiArray 
{ 
    private: 
     typedef T cols[height]; 
     cols * data; 
    public: 
     T& operator() (int x, int y) { return data[x][y]; } 
     MultiArray() { data = new cols[width]; } 
     ~MultiArray() { delete [] data; } 
};

Uso:

MultiArray<int, 10, 10> myArray; 
myArray(2, 3) = 4; 
cout << myArray(2, 3);

edición: y, mientras yo estoy en ello, aquí es la configuración que puede utilizar si no lo hace conocer los límites de la matriz hasta el tiempo de ejecución:

template<typename T> 
class Array2D 
{ 
    private: 
     const int width; 
     T * data; 
    public: 
     T& operator() (int x, int y) { return data[y*width + x]; } 
     Array2D(const int w, const int h) : width(w) { data = new T[w*h]; } 
     ~Array2D() { delete [] data; } 
};

Uso:

Array2D myArray(10, 10); 
myArray(3, 4) = 42; 
cout << myArray(3, 4);
0

Puede indexar una dimensión como una dimensional de 2, 3 o N si solo tiene espacio sobre la cantidad correcta de elementos. Por ejemplo, si tengo 10 filas y 10 columnas, sé que si estoy en la fila 3 tendré que revisar al menos 30 elementos para acceder a ella.

De alguna manera prefiero esta notación para matrices 2D simples ya que no tengo que preocuparme por los niveles anidados de los punteros. La desventaja es la notación del índice más desordenado.He aquí un ejemplo de una matriz 2D con n filas ym columnas:

int *matrix = new int[n*m]; 

//set element (3,7) to 10 
matrix[3*m+7] = 10; 

//print the matrix 
for (int i = 0; i < n; i++) { 
    for (int j = 0; j < m; j++) { 
    cout << matrix[i*m+j] << ' '; 
    } 
    cout << '\n'; 
} 
3

Me sorprende que nadie ha mencionado boost::multi_array todavía. Necesitaba un arreglo en 2D en un programa la semana pasada, y descubrí que era mucho más fácil y más rápido de codificar que las soluciones caseras que he encontrado antes (todas mencionadas en otros comentarios) .

0

Mi pregunta here cubre en su mayoría el mismo tema bastante bien gracias a algunas respuestas excelentes. Sin embargo, no cubre matrices N-Dimensionales, que tampoco he visto abordar en las respuestas aquí, pero eso sería útil.

6

¿Qué le parece usar Boost.Multiarray? ¡Creo que responde bastante bien a tu necesidad! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction

Aquí es un extracto de la página de documentación:

#include <boost/multi_array.hpp> 

#include <cassert> 

int main() 

{ 

    // Create a 3D array that is 3 x 4 x 2 

    typedef boost::multi_array< double, 3 > array_type; 

    typedef array_type::index index; 

    array_type A(boost::extents[3][4][2]); 


    // Assign values to the elements 

    int values = 0; 

    for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j) 

     for(index k = 0; k != 2; ++k) 

     A[i][j][k] = values++; 

    // Verify values 

    int verify = 0; 

    for(index i = 0; i != 3; ++i) 

    for(index j = 0; j != 4; ++j) 

     for(index k = 0; k != 2; ++k) 

     assert(A[i][j][k] == verify++); 

    return 0; 

} 
2

Como otra alternativa, STLSoft incluye una clase fixed_array_2d (así como versiones 3D y 4D). En comparación con las soluciones caseras proporcionadas aquí, tiene una implementación similar pero un conjunto de características más completo (soporte completo para iteradores, etc.). Comparado con boost :: multi_array, es más liviano y más fácil en compiladores de C++ que no cumplen con los requisitos, pero (intencionalmente) carece de algunas de las características de multi_array.

0

Esta es una reproducción de una publicación en otro hilo. Hace exactamente lo que quiere, sin necesidad de conocer las dimensiones de la matriz antes de tiempo, y sin usar boost o STL.

Aquí hay una rutina que asigna la matriz 3D de la dimensión N1 x N2 x N3 en el espacio contiguo de la memoria al mismo tiempo que le permite la sintaxis a [i] [j] [k] para el acceso del operador. La matriz es dinámica pero continua, por lo que es una gran ventaja sobre el vector <> enfoque y bucles de llamadas nuevas [].

template <class T> T ***Create3D(int N1, int N2, int N3) 
{ 
    T *** array = new T ** [N1]; 

    array[0] = new T * [N1*N2]; 

    array[0][0] = new T [N1*N2*N3]; 

    int i,j,k; 

    for(i = 0; i < N1; i++) { 

     if (i < N1 -1) { 

      array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]); 

      array[i+1] = &(array[0][(i+1)*N2]); 

     } 

     for(j = 0; j < N2; j++) {  
      if (j > 0) array[i][j] = array[i][j-1] + N3; 
     } 

    } 

    cout << endl; 
    return array; 
}; 

template <class T> void Delete3D(T ***array) { 
    delete[] array[0][0]; 
    delete[] array[0]; 
    delete[] array; 
}; 

Y más tarde en su rutina de ejecución ...

int *** array3d; 
int N1=4, N2=3, N3=2; 

int elementNumber = 0; 

array3d = Create3D<int>(N1,N2,N3); 

//equivalently, a 'flat' array could be obtained with 
//int * array = array3d[0][0]; 

cout << "{" << endl; 
for (i=0; i<N1; i++) { 
    cout << "{"; 
    for (j=0; j<N2; j++) { 
     cout << "{"; 
     for (k=0; k<N3; k++) { 
      array3d[i][j][k] = elementNumber++; 
      cout << setw(4) << array3d[i][j][k] << " "; 

      //or if you're using the flat array: 
      //array[i*N2*N3 + j*N3 + k] = elementNumber++; 

     } 
     cout << "}"; 
    } 
    cout << "}"; 
    cout << endl ; 
} 
cout << "}" << endl; 

Delete3D(array3d); 

proporciona la salida:

{ 
{{ 0 1 }{ 2 3 }{ 4 5 }} 
{{ 6 7 }{ 8 9 }{ 10 11 }} 
{{ 12 13 }{ 14 15 }{ 16 17 }} 
{{ 18 19 }{ 20 21 }{ 22 23 }} 
} 
Cuestiones relacionadas