¿Cómo declaro una matriz 2d usando new?
Por ejemplo, para una matriz "normal" yo haría:
int* ary = new int[Size]
pero
int** ary = new int[sizeY][sizeX]
a) no funciona / compila yb) no logra lo que:
int ary[sizeY][sizeX]
hace.
c++
arrays
multidimensional-array
dynamic-allocation
usuario20844
fuente
fuente
Respuestas:
Una matriz 2D dinámica es básicamente una matriz de punteros a matrices . Puede inicializarlo usando un bucle, como este:
Lo anterior, para
colCount= 5
yrowCount = 4
, produciría lo siguiente:fuente
new
se crea en el montón y debe ser desasignadadelete
, solo tenga esto en cuenta y asegúrese de eliminar esta memoria del montón cuando haya terminado para evitar fugas.T (*ptr)[M] = new T[N][M];
es la solución correcta ... Ninguna cantidad de matrices de punteros será igual a una matriz de matrices ...debiera ser:
y luego limpiar sería:
EDITAR: como Dietrich Epp señaló en los comentarios, esta no es exactamente una solución ligera. Un enfoque alternativo sería utilizar un gran bloque de memoria:
fuente
i*sizeX+j
? Si recuerdo correctamente, con el orden principal de la fila debería ser row * numColumns + col.Aunque esta respuesta popular le dará la sintaxis de indexación deseada, es doblemente ineficiente: grande y lenta tanto en espacio como en tiempo. Hay una mejor manera
Por qué esa respuesta es grande y lenta
La solución propuesta es crear una matriz dinámica de punteros, luego inicializar cada puntero en su propia matriz dinámica independiente. La ventaja de este enfoque es que le brinda la sintaxis de indexación a la que está acostumbrado, por lo que si desea encontrar el valor de la matriz en la posición x, y, usted dice:
Esto funciona porque la matriz [x] devuelve un puntero a una matriz, que luego se indexa con [y]. Desglosándolo:
Conveniente, si? Nos gusta nuestra sintaxis [x] [y].
Pero la solución tiene una gran desventaja , que es tanto gorda como lenta.
¿Por qué?
La razón por la que es gorda y lenta es en realidad la misma. Cada "fila" en la matriz es una matriz dinámica asignada por separado. Hacer una asignación de montón es costoso tanto en tiempo como en espacio. El asignador toma tiempo para realizar la asignación, a veces ejecuta algoritmos O (n) para hacerlo. Y el asignador "rellena" cada una de sus matrices de filas con bytes adicionales para la contabilidad y la alineación. Ese espacio extra cuesta ... bueno ... espacio extra. El desasignante también tomará más tiempo cuando vaya a desasignar la matriz, liberando minuciosamente cada asignación de fila individual. Me hace sudar solo de pensarlo.
Hay otra razón por la que es lento. Estas asignaciones separadas tienden a vivir en partes discontinuas de la memoria. Una fila puede estar en la dirección 1,000, otra en la dirección 100,000: se entiende la idea. Esto significa que cuando atraviesas la matriz, saltas a través de la memoria como una persona salvaje. Esto tiende a provocar errores de caché que ralentizan enormemente el tiempo de procesamiento.
Entonces, si debe tener su linda sintaxis de indexación [x] [y], use esa solución. Si desea rapidez y pequeñez (y si no le importan, ¿por qué está trabajando en C ++?), Necesita una solución diferente.
Una solución diferente
La mejor solución es asignar toda su matriz como una única matriz dinámica, luego usar matemática de indexación inteligente (ligeramente) para acceder a las celdas. La matemática de indexación es solo muy levemente inteligente; no, no es nada inteligente: es obvio.
Dada esta
index()
función (que estoy imaginando es un miembro de una clase porque necesita conocer elm_width
de su matriz), puede acceder a las celdas dentro de su matriz. La matriz de matriz se asigna de esta manera:Entonces, el equivalente de esto en la solución lenta y gorda:
... es esto en la solución rápida y pequeña:
Triste, lo se. Pero te acostumbrarás. Y tu CPU te lo agradecerá.
fuente
class Matrix { int* array; int m_width; public: Matrix( int w, int h ) : m_width( w ), array( new int[ w * h ] ) {} ~Matrix() { delete[] array; } int at( int x, int y ) const { return array[ index( x, y ) ]; } protected: int index( int x, int y ) const { return x + m_width * y; } };
si endereza ese código, podría tener sentido y podría arrojar luz sobre la respuesta anterior.#define ROW_COL_TO_INDEX(row, col, num_cols) (row*num_cols + col)
luego puede usarlo comoint COLS = 4; A[ ROW_COL_TO_INDEX(r, c, COLS) ] = 75;
La sobrecarga realmente afecta cuando hacemos multiplicaciones de matriz que son de complejidad O (n ^ 3) u O (n ^ 2.81) para el algoritmo de Strassen .a[x][y]
, lo que realmente está haciendo es*(*(a + x) + y)
: dos adiciones y dos recuperaciones de memoria. Cona[index(x, y)]
lo que realmente está haciendo es*(a + x + w*y)
: dos adiciones, una multiplicación y una recuperación de memoria. Este último es a menudo preferible, por las razones expuestas en esta respuesta (es decir, cambiar la recuperación de memoria adicional con una multiplicación vale la pena, especialmente porque los datos no están fragmentados y, por lo tanto, no se pierde la memoria caché).En C ++ 11 es posible:
De esta manera, la memoria no se inicializa. Para inicializar, haga esto:
Programa de muestra (compilar con "g ++ -std = c ++ 11"):
Salida:
fuente
using arr2d = double(*)[2]; arr2d array = new double[M][N];
double (*)[M][N]
odouble(*)[][N]
con M, N siendo expresiones constantes.Supongo, por su ejemplo de matriz estática, que desea una matriz rectangular y no dentada. Puedes usar lo siguiente:
Luego puede acceder a elementos como:
No olvides usar delete [] on
ary
.fuente
Hay dos técnicas generales que recomendaría para esto en C ++ 11 y superior, una para las dimensiones de tiempo de compilación y otra para el tiempo de ejecución. Ambas respuestas suponen que desea matrices bidimensionales uniformes (no dentadas).
Dimensiones del tiempo de compilación
Use un
std::array
destd::array
y luego usenew
para ponerlo en el montón:Nuevamente, esto solo funciona si los tamaños de las dimensiones se conocen en tiempo de compilación.
Dimensiones del tiempo de ejecución
La mejor manera de lograr una matriz bidimensional con tamaños que solo se conocen en tiempo de ejecución es envolverla en una clase. La clase asignará una matriz 1d y luego se sobrecargará
operator []
para proporcionar indexación para la primera dimensión. Esto funciona porque en C ++ una matriz 2D es mayor de fila:(Tomado de http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )
Una secuencia contigua de memoria es buena por razones de rendimiento y también es fácil de limpiar. Aquí hay una clase de ejemplo que omite muchos métodos útiles pero muestra la idea básica:
Entonces creamos una matriz con
std::make_unique<int[]>(rows * columns)
entradas. Sobrecargamosoperator []
lo que indexará la fila por nosotros. Devuelve unint *
que apunta al comienzo de la fila, que luego puede desreferenciarse como normal para la columna. Tenga en cuenta quemake_unique
primero se envía en C ++ 14, pero puede rellenarlo en C ++ 11 si es necesario.También es común que este tipo de estructuras se sobrecarguen
operator()
también:Técnicamente no he utilizado
new
aquí, pero es trivial para pasar destd::unique_ptr<int[]>
aint *
y el usonew
/delete
.fuente
std::array
destd::array
s:std::array<std::array<int, columns> rows>
.asserts
para las compilaciones de depuración para verificar los accesos a la memoria, etc. Estas adiciones generalmente hacen que sea más fácil y más agradable trabajar con ellas.make_unique
lugar denew/delete
.Esta pregunta me estaba molestando: es un problema bastante común que ya debería existir una buena solución, algo mejor que el vector de vectores o rodar su propia indexación de matriz.
Cuando algo debería existir en C ++ pero no existe, el primer lugar para buscar es boost.org . Allí me encontré con el Boost Multidimensional matriz Biblioteca,
multi_array
. Incluso incluye unamulti_array_ref
clase que puede usarse para envolver su propio búfer de matriz unidimensional.fuente
auto
palabra clave. Me sorprende que no hayan intentado abordar matrices 2D, especialmente porque Boost ya ha mostrado el camino.¿Por qué no usar STL: vector? Tan fácil, y no necesita eliminar el vector.
También puedes inicializar las 'matrices', solo dale un valor predeterminado
Fuente: ¿Cómo crear matrices dimensionales de 2, 3 (o múltiples) en C / C ++?
fuente
Una matriz 2D es básicamente una matriz 1D de punteros, donde cada puntero apunta a una matriz 1D, que contendrá los datos reales.
Aquí N es fila y M es columna.
asignación dinámica
llenar
impresión
gratis
fuente
¿Cómo asignar una matriz multidimensional contigua en GNU C ++? Hay una extensión GNU que permite que funcione la sintaxis "estándar".
Parece que el problema proviene del operador new []. Asegúrese de usar el operador new en su lugar:
Y eso es todo: obtienes una matriz multidimensional compatible con C ...
fuente
double (*in)[m][n] = (double (*)[m][n])new double[k*m*n];
tampoco funciona. Recibo errores C2057, C2540n
porque no se conoce en el momento de la compilación. No entiendo por qué no puedo hacerlo, porque la memoria se asigna correctamente y solo son punteros para manejar esta memoria convenientemente. (VS 2010)gcc
me engañó cuando escribí esto: el suministro-std=c++11
no es suficiente para activar la estricta conformidad estándar, también-pedantic-errors
se requiere. Sin la bandera posterior,gcc
acepta felizmente el elenco, aunque de hecho no está de acuerdo con el estándar C ++. Con lo que sé ahora, solo puedo recomendar volver a C cuando haga cosas que dependen en gran medida de los arreglos multidimensionales. C99 es mucho más poderoso en este sentido que incluso C ++ 17 lo será.typedef es tu amigo
Después de volver y mirar muchas de las otras respuestas, descubrí que se necesita una explicación más profunda, ya que muchas de las otras respuestas sufren problemas de rendimiento o lo obligan a usar una sintaxis inusual o onerosa para declarar la matriz, o acceder a la matriz. elementos (o todo lo anterior).
En primer lugar, esta respuesta supone que conoce las dimensiones de la matriz en tiempo de compilación. Si lo hace, esta es la mejor solución, ya que proporcionará el mejor rendimiento y le permitirá usar la sintaxis de matriz estándar para acceder a los elementos de la matriz .
La razón por la que esto brinda el mejor rendimiento es porque asigna todos los arreglos como un bloque contiguo de memoria, lo que significa que es probable que tenga menos errores de página y una mejor ubicación espacial. La asignación en un bucle puede hacer que las matrices individuales terminen dispersas en varias páginas no contiguas a través del espacio de memoria virtual, ya que el bucle de asignación podría ser interrumpido (posiblemente varias veces) por otros subprocesos o procesos, o simplemente debido a la discreción del el asignador llena pequeños y vacíos bloques de memoria que tiene disponibles.
Los otros beneficios son una sintaxis de declaración simple y una sintaxis de acceso a matriz estándar.
En C ++ usando nuevo:
O estilo C usando calloc:
fuente
Este problema me ha molestado durante 15 años, y todas las soluciones suministradas no fueron satisfactorias para mí. ¿Cómo se crea una matriz dinámica multidimensional contiguamente en la memoria? Hoy finalmente encontré la respuesta. Usando el siguiente código, puede hacer exactamente eso:
Cuando invoque el programa con los valores sizeX = 20 y sizeY = 15, el resultado será el siguiente:
Como puede ver, la matriz multidimensional se encuentra contiguamente en la memoria, y no hay dos direcciones de memoria superpuestas. Incluso la rutina para liberar la matriz es más simple que la forma estándar de asignar dinámicamente memoria para cada columna (o fila, dependiendo de cómo vea la matriz). Dado que el conjunto consiste básicamente en dos conjuntos lineales, solo estos dos tienen que ser (y pueden ser) liberados.
Este método puede extenderse por más de dos dimensiones con el mismo concepto. No lo haré aquí, pero cuando entiendes la idea, es una tarea simple.
Espero que este código te ayude tanto como a mí.
fuente
array2d[i] = buffer + i * sizeX
. Esto ayuda en un pequeño grado, pero en el código que usa la matriz, el compilador no puede simplemente incrementar los punteros para escanear la matriz.make_unique<int[]>(sizeX*sizeY)
para configurar el almacenamiento contiguo ymake_unique<int*[]>(sizeX)
para configurar el almacenamiento de los punteros (que deberían asignarse de la misma manera que se muestra). Esto lo libera del requisito de llamardelete[]
dos veces al final.temp
? Teniendo en cuenta los beneficios (matriz continua 2d con dimensiones desconocidas en el momento de la compilación), no estoy seguro de que me importe tenerla colgando. No entendí lo que @PeterCordes quiere decirextra layer of indirection
, ¿qué es? Por qué el paréntesisarray2d[i] = (temp + i * sizeX)
;El propósito de esta respuesta no es agregar nada nuevo que los otros no cubran, sino extender la respuesta de @Kevin Loney.
Podrías usar la declaración ligera:
y la sintaxis de acceso será:
pero esto es engorroso para la mayoría y puede generar confusión. Por lo tanto, puede definir una macro de la siguiente manera:
Ahora puede acceder a la matriz usando una sintaxis muy similar
ary(i, j) // means ary[i][j]
. Esto tiene las ventajas de ser simple y hermoso, y al mismo tiempo, usar expresiones en lugar de los índices también es más simple y menos confuso.Para acceder, digamos, ary [2 + 5] [3 + 8], puede escribir en
ary(2+5, 3+8)
lugar del aspecto complejo,ary[(2+5)*SizeY + (3+8)]
es decir, ahorra paréntesis y ayuda a la legibilidad.Advertencias:
SizeY
debe pasar con el mismo nombre (o en su lugar, declararse como una variable global).O, si necesita usar la matriz en múltiples funciones, entonces podría agregar SizeY también como otro parámetro en la definición de macro de la siguiente manera:
Tienes la idea. Por supuesto, esto se vuelve demasiado largo para ser útil, pero aún puede evitar la confusión de + y *.
Esto no se recomienda definitivamente, y será condenado como una mala práctica por los usuarios más experimentados, pero no pude resistirme a compartirlo debido a su elegancia.
Editar:
si desea una solución portátil que funcione para cualquier número de matrices, puede usar esta sintaxis:
y luego puede pasar cualquier matriz a la llamada, con cualquier tamaño utilizando la sintaxis de acceso:
PD: He probado estos, y la misma sintaxis funciona (como lvalue y rvalue) en los compiladores g ++ 14 y g ++ 11.
fuente
Intenta hacer esto:
fuente
Aquí tengo dos opciones. El primero muestra el concepto de una matriz de matrices o puntero de punteros. Prefiero el segundo porque las direcciones son contiguas, como se puede ver en la imagen.
fuente
Si su proyecto es CLI (Common Language Runtime Support) , entonces:
Puede usar la clase de matriz, no la que obtiene cuando escribe:
En otras palabras, no la clase de matriz no administrada que se obtiene cuando se usa el espacio de nombres estándar y cuando se incluye el encabezado de matriz, no la clase de matriz no administrada definida en el espacio de nombres estándar y en el encabezado de matriz, sino la matriz de clase administrada de la CLI.
Con esta clase, puede crear una matriz de cualquier rango que desee.
El siguiente código a continuación crea una nueva matriz bidimensional de 2 filas y 3 columnas y de tipo int, y lo llamo "arr":
Ahora puede acceder a los elementos de la matriz, asígnele un nombre y escriba solo un paréntesis cuadrado
[]
y, dentro de ellos, agregue la fila y la columna, y sepárelos con la coma,
.El siguiente código a continuación accede a un elemento en la segunda fila y la primera columna de la matriz que ya creé en el código anterior:
escribir solo esta línea es leer el valor en esa celda, es decir, obtener el valor en esta celda, pero si agrega el igual
=
signo , está a punto de escribir el valor en esa celda, es decir, establecer el valor en esta celda. También puede usar los operadores + =, - =, * = y / =, por supuesto, solo para números (int, float, double, __int16, __int32, __int64 y etc.), pero seguro que ya lo sabe.Si su proyecto no es CLI, puede usar la clase de matriz no administrada del espacio de nombres estándar, si usted
#include <array>
, por supuesto, pero el problema es que esta clase de matriz es diferente de la matriz CLI. Crear matriz de este tipo es igual que la CLI, excepto que tendrá que eliminar el^
signo y lagcnew
palabra clave. Pero desafortunadamente, el segundo parámetro int<>
entre paréntesis especifica la longitud (es decir, el tamaño) de la matriz, ¡ no su rango!No hay forma de especificar el rango en este tipo de matriz, el rango es solo la característica de la matriz CLI . .
La matriz estándar se comporta como la matriz normal en c ++, que usted define con puntero, por ejemplo
int*
y luego:new int[size]
o sin puntero:int arr[size]
pero, a diferencia de la matriz normal de c ++, la matriz estándar proporciona funciones que puede usar con los elementos de la matriz, como relleno, inicio, fin, tamaño, etc., pero la matriz normal no proporciona nada .Pero aún así, las matrices estándar son matrices unidimensionales, como las matrices normales de c ++. Pero gracias a las soluciones que los otros chicos sugieren sobre cómo puede hacer la matriz unidimensional normal de c ++ en una matriz bidimensional, podemos adaptar las mismas ideas a la matriz estándar, por ejemplo, de acuerdo con la idea de Mehrdad Afshari, podemos escribir el siguiente código:
Esta línea de código crea un "conjunto malabarizado" , que es un conjunto unidimensional en el que cada una de sus celdas es o apunta a otro conjunto unidimensional.
Si todas las matrices unidimensionales en una matriz unidimensional son iguales en su longitud / tamaño, entonces puede tratar la variable array2d como una matriz bidimensional real, además puede usar los métodos especiales para tratar filas o columnas, depende de cómo lo vea. en mente, en la matriz 2D, esa matriz estándar es compatible.
También puede usar la solución de Kevin Loney:
pero si usa la matriz estándar, el código debe verse diferente:
Y todavía tiene las funciones únicas de la matriz estándar.
Tenga en cuenta que aún puede acceder a los elementos de la matriz estándar utilizando los
[]
paréntesis, y no tiene que llamar a laat
función. También puede definir y asignar una nueva variable int que calculará y mantendrá el número total de elementos en la matriz estándar, y usará su valor, en lugar de repetirsizeX*sizeY
Puede definir su propia clase genérica de matriz bidimensional y definir el constructor de la clase de matriz bidimensional para recibir dos enteros para especificar el número de filas y columnas en la nueva matriz bidimensional, y definir la función get que recibe dos parámetros de entero que accede a un elemento en la matriz bidimensional y devuelve su valor, y establece una función que recibe tres parámetros, que los dos primeros son enteros que especifican la fila y la columna en la matriz bidimensional, y el tercer parámetro es el nuevo valor de elemento. Su tipo depende del tipo que elija en la clase genérica.
Usted será capaz de poner en práctica todo esto mediante el uso de ya sea el normal c ++ array (punteros o sin ella) o la matriz ETS y el uso una de las ideas que otras personas sugirieron, y que sea fácil de usar como la matriz de la CLI, o como los dos matriz dimensional que puede definir, asignar y usar en C #.
fuente
Comience definiendo la matriz utilizando punteros (Línea 1):
fuente
El siguiente ejemplo puede ayudar,
fuente
Si desea una matriz 2D de enteros, qué elementos se asignan secuencialmente en la memoria, debe declararlo como
donde en lugar de x puede escribir cualquier dimensión, pero n debe ser igual en dos lugares. Ejemplo
debe imprimir 6.
fuente
Te he dejado una solución que funciona mejor para mí, en ciertos casos. Especialmente si uno conoce [el tamaño de?] Una dimensión de la matriz. Muy útil para un conjunto de caracteres, por ejemplo, si necesitamos un conjunto de diferentes tamaños de conjuntos de caracteres [20].
La clave son los paréntesis en la declaración de la matriz.
fuente
Utilicé este sistema no elegante pero RÁPIDO, FÁCIL y FUNCIONAMIENTO No veo por qué no puede funcionar porque la única forma en que el sistema permite crear una matriz de gran tamaño y acceder a las partes es sin cortarla en partes:
fuente
No estoy seguro si no se proporcionó la siguiente respuesta, pero decidí agregar algunas optimizaciones locales a la asignación de la matriz 2d (por ejemplo, una matriz cuadrada se realiza a través de una sola asignación):
int** mat = new int*[n]; mat[0] = new int [n * n];
Sin embargo, la eliminación es así debido a la linealidad de la asignación anterior:
delete [] mat[0]; delete [] mat;
fuente
declarando una matriz 2D dinámicamente:
Ahora en el código anterior tomamos un puntero doble y le asignamos una memoria dinámica y le dimos un valor de las columnas. Aquí la memoria asignada es solo para las columnas, ahora para las filas solo necesitamos un bucle for y asignar el valor para cada fila de una memoria dinámica. Ahora podemos usar el puntero de la misma manera que usamos una matriz 2D. En el ejemplo anterior, asignamos números aleatorios a nuestra matriz 2D (puntero). Se trata de DMA de matriz 2D.
fuente
Estoy usando esto al crear una matriz dinámica. Si tienes una clase o una estructura. Y esto funciona. Ejemplo:
fuente