¿Alguien sabe cómo puedo usar asignada dinámicamente múltiples dimensiones de las matrices, el uso de C? Es eso posible?

InformationsquelleAutor rpf | 2009-05-27

9 Comentarios

  1. 74

    Con la asignación dinámica, el uso de malloc:

    int** x;
    
    x = malloc(dimension1_max * sizeof(int*));
    for (int i = 0; i < dimension1_max; i++) {
      x[i] = malloc(dimension2_max * sizeof(int));
    }
    
    [...]
    
    for (int i = 0; i < dimension1_max; i++) {
      free(x[i]);
    }
    free(x);

    Asigna una matriz 2D de tamaño dimension1_max * dimension2_max. Así, por ejemplo, si desea 640*480 de la matriz (f.e. los píxeles de una imagen), el uso de dimension1_max = 640, dimension2_max = 480. A continuación puede acceder a la matriz de uso de la x[d1][d2] donde d1 = 0..639, d2 = 0..479.

    Pero una búsqueda en MODO o Google revela también otras posibilidades, por ejemplo en este ASÍ que la pregunta

    Tenga en cuenta que la matriz no asignar una región contigua de memoria (640*480 bytes) en ese caso lo que podría dar problemas con las funciones que asume este. Así que para obtener la matriz satisface la condición, reemplace el malloc bloque encima con esto:

    int** x;
    int* temp;
    
    x = malloc(dimension1_max * sizeof(int*));
    temp = malloc(dimension1_max * dimension2_max * sizeof(int));
    for (int i = 0; i < dimension1_max; i++) {
      x[i] = temp + (i * dimension2_max);
    }
    
    [...]
    
    free(temp);
    free(x);
    • Esto no compilará, deberá declarar x como «int **», no «int[][]».
    • ¿Qué significa esto exactamente? ¿Qué es dimension1_max y dimension2_max? ¿Qué hace el primer «para»?
    • Gracias, Adam, yo sabía que algo estaba mal, aunque ya lo he corregido el primer sizeof a int* en lugar de int.
    • No es una matriz multidimensional – es la matriz de punteros a int, o una matriz de matrices. Para asignar memoria para el real matriz 2D necesita usar malloc(dim1 * dim2 * sizeof(int)). Si alguna función espera puntero a matriz 2D, como foo(int * bar[5][6]) y usted se pasa de la x, extraño las cosas van a suceder. Consulte en.wikipedia.org/wiki/C_syntax#Multidimensional_arrays
    • Ah, entiendo lo que quieres decir. He añadido otro ejemplo donde una región contigua de memoria se facilitan y, además, se ha corregido el de las llamadas a malloc que no estaban fundidas a int*/int**.
    • ¿Por qué te casting malloc
    • En C puro, no lanzas malloc, pero en C++ es necesario, vea stackoverflow.com/questions/605845/… – gracias por la captura, lo voy a editar como esto es un puro C pregunta.
    • Cómo llega por primera malloc :x = malloc(dimension1_max * sizeof(int*));, utiliza sizeof(int*), cuando se utiliza sólo sizeof(int) para el segundo malloc: temp = malloc(dimension1_max * dimension2_max * sizeof(int));…es decir la primera tiene un * y el segundo no
    • El primero asigna espacio para punteros a enteros, el segundo, uno de los enteros.
    • Si yo estaba tratando de hacer una matriz 2D de char, sería el mismo? La capa exterior podría ser un puntero a char y la capa interna está char?
    • Sí, eso es correcto, la capa externa de puntos para el primer elemento de la capa interna de cada fila/columna.
    • Esto hace no asignar una matriz 2D, pero una matriz de puntero plus matrices apunta. Medio de apuntar es muy diferente, tiene sobrecarga de memoria y probablemente menos eficaz.
    • ¿Cómo liberar la memoria con la segunda opción? (si usted ya no tendrá acceso a temp)
    • Si usted ya no tendrá acceso a temp, no se puede liberar la memoria. En la segunda opción, x y temp son dos completamente independiente de la memoria de las regiones y tendrás que liberar a ambos usando free. Voy a editar la respuesta a mostrar cómo gratis aquí.
    • Sin duda va a tener todavía x, y por lo tanto x[0] que se inicializa con x[0] = temp, ¿ free(x[0]) liberaría a toda la matriz?

  2. 73

    Desde C99, C son matrices 2D con la dinámica de los límites. Si desea evitar que esa bestia se almacena en la pila (que debería), les puede asignar fácilmente en un ir como el siguiente

    double (*A)[n] = malloc(sizeof(double[n][n]));

    y eso es todo. Usted puede entonces utilizar fácilmente como usted se utilizan para 2D matrices con algo como A[i][j]. Y no hay que olvidar que uno al final

    free(A);

    Randy Meyers escribió una serie de artículos explicando longitud variable matrices (VLAs).

    • Partes 2, 3 y 4 de Meyers de la serie también están disponibles desde el Dr. Dobbs.
    • Aunque este es un bonito y elegante solución, la belleza está más en la declaración de A que en la asignación real; en particular, no 2-D de la matriz se asigna en cualquier lugar, y mucho menos una forma dinámica de tamaño uno. El malloc sólo asigna un tramo lineal de un tipo de memoria adecuadamente alineados para nada; la dirección A se inicializa con que puede venir de cualquier fuente (pozo, debido a problemas de aliasing yo supongo que podría provenir de una matriz unidimensional de tipo char o doble, o de una «verdadera» 2-dimensiones de la matriz). El tiempo de ejecución de sizeof sólo calcula un número (siempre la de la derecha, claro) ;-).
    • Gran respuesta! Además: En tu ejemplo, ambas dimensiones tienen el mismo tamaño n. Con diferentes tamaños, tendría este aspecto: double (*a)[y] = malloc(sizeof(double[x][y]));. Con tres dimensiones: double (*a)[y][z] = malloc(sizeof(double[x][y][z]));. Y así sucesivamente.
  3. 51

    Fundamentos

    Matrices en c se declaran y se accede utilizando el [] operador. Así que

    int ary1[5];

    declara una matriz de 5 números enteros. Los elementos se numeran a partir de cero, por lo que ary1[0] es el primer elemento, y ary1[4] es el último elemento. Nota 1: no Hay inicialización predeterminada, por lo que la memoria ocupada por la matriz inicial puede contener nada. Note2: ary1[5] accesos a memoria en un estado indefinido (que incluso pueden no ser accesibles a usted), así que no lo hagas!

    Múltiples dimensiones de las matrices son implementados como un array de arrays (matrices (de … ) ). Así

    float ary2[3][5];

    declara una matriz de 3 arrays de una dimensión de 5 números de punto flotante de cada uno. Ahora ary2[0][0] es el primer elemento de la primera matriz, ary2[0][4] es el último elemento de la primera matriz, y ary2[2][4] es el último elemento de la última matriz. El ’89 estándar requiere que estos datos sean contiguos (sec. A8.6.2 en la página 216 de mi K&R 2do. ed.) pero parece ser independiente de relleno.

    Tratando de ir dinámica en más de una dimensión

    Si usted no sabe el tamaño de la matriz en tiempo de compilación, usted querrá para asignar dinámicamente la matriz. Es tentador intentar

    double *buf3;
    buf3 = malloc(3*5*sizeof(double));
    /* error checking goes here */

    que debería funcionar si el compilador no almohadilla de la asignación (palo de espacio extra entre las matrices unidimensionales). Podría ser más seguro para ir con:

    double *buf4;
    buf4 = malloc(sizeof(double[3][5]));
    /* error checking */

    pero de cualquier manera el truco viene a eliminar la referencia de tiempo. Usted no puede escribir buf[i][j] porque buf tiene el tipo equivocado. Tampoco puede utilizar

    double **hdl4 = (double**)buf;
    hdl4[2][3] = 0; /* Wrong! */

    porque el compilador espera hdl4 a ser la dirección de una dirección de un doble. Tampoco puede utilizar double incomplete_ary4[][]; porque esto es un error;

    Entonces, ¿qué puede hacer?

    • Hacer la fila y la columna de la aritmética mismo
    • Asignar y hacer el trabajo en una función
    • El uso de una matriz de punteros (el mecanismo qrdl está hablando)

    Hacer los cálculos usted mismo

    Simplemente calcular desplazamiento de memoria a cada elemento como este:

      for (i=0; i<3; ++i){
         for(j=0; j<3; ++j){
            buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                                 padding in this case */
         }
      }

    Asignar y hacer el trabajo en una función

    Definir una función que toma el tamaño necesario como un argumento y continuar de forma normal

    void dary(int x, int y){
      double ary4[x][y];
      ary4[2][3] = 5;
    }

    De curso, en este caso ary4 es una variable local y no se puede volver: todo el trabajo con la matriz debe ser hecho en función de llamada de funciones que se llamadas.

    Una matriz de punteros

    Considere esto:

    double **hdl5 = malloc(3*sizeof(double*));
    /* Error checking */
    for (i=0; i<3; ++i){
       hdl5[i] = malloc(5*sizeof(double))
       /* Error checking */
    }

    Ahora hdl5 apunta a un array de punteros de cada uno de los cuales apunta a un array de doubles. El poco frío es que se puede utilizar la matriz de dos dimensiones de la notación acceso a esta estructura—hdl5[0][2] obtiene la media de los elementos de la primera fila—pero esto no es-el-menos de un tipo diferente de objeto de una matriz de dos dimensiones declarado por double ary[3][5];.

    Esta estructura es más flexible, a continuación, una matriz bidimensional (ya que las filas no necesitan ser de la misma longitud), pero el acceso es generalmente será más lento y requiere más memoria (usted necesita un lugar para celebrar el intermedio punteros).

    Nota que ya no he de instalación de las protecciones tendrás que seguir la pista de el tamaño de todas las matrices de sí mismo.

    Aritmética

    c no proporciona soporte para el vector, una matriz o tensor de matemáticas, usted tendrá que aplicar a ti mismo, o incorporar una biblioteca.

    La multiplicación por un factor de escala y de la suma y resta de matrices de la misma fila son fácil: basta con recorrer los elementos y realizar la operación a medida que avanza. Interior de los productos son de igual manera recta hacia adelante.

    Exterior de productos significan más bucles.

    • Sólo un punto – matriz de matrices es la matriz de punteros, no es una verdadera matriz multidimensional. en.wikipedia.org/wiki/C_syntax#Multidimensional_arrays
    • Como leí el estándar int **a1; y, int *a2[i]; int a3[n][m]; son diferentes criaturas con diferentes semántica. El último uno se asigna un bloque de continguous (posiblemente collar) de memoria sin un conjunto separado de intermedio punteros… Intente printf(«%d\n»,sizeof(int[3][5])/sizeof(int));
    • ¿»Asignar en función» de trabajo? Cómo sería el compilador sabe cuánta memoria para asignar en la pila de la matriz ary4 si x e y son desconocidos?
    • Er … x y y son conocidos en tiempo de ejecución y el compilador no se limita a cambiar el tamaño del marco de pila de una sola vez. Intente. Por supuesto que no pueda volver a la matriz, usted tiene que hacer todo el trabajo en la función, así que mi texto es un poco engañoso. Voy a editar para corregir eso.
    • Yo tenía esta idea de que el compilador necesita saber el tamaño de la matriz en tiempo de compilación para asignar memoria para él. Acabo de probar esto y comprobado el ensamblado generado. Como usted ha dicho, es de los tamaños del marco de pila dependiendo de los argumentos de entrada. Gracias!
    • Para lo que vale, creo que el compilador no necesita saber el tamaño de un ámbito global de las matrices en tiempo de compilación.

  4. 9

    Si usted sabe el número de columnas en tiempo de compilación, es bastante simple:

    #define COLS ...
    ...
    size_t rows;
    //get number of rows
    T (*ap)[COLS] = malloc(sizeof *ap * rows); //ap is a *pointer to an array* of T

    Puede tratar ap como cualquier matriz 2D:

    ap[i][j] = x;

    Cuando hayas terminado de desasignar como

    free(ap);

    Si usted no sabe el número de columnas en tiempo de compilación, pero se está trabajando con una C99 compilador o un C2011 compilador que soporta arreglos de longitud variable, es bastante simple:

    size_t rows;
    size_t cols;
    //get rows and cols
    T (*ap)[cols] = malloc(sizeof *ap * rows);
    ...
    ap[i][j] = x;
    ...
    free(ap);

    Si usted no sabe el número de columnas en tiempo de compilación y estás trabajando con una versión de C que no es compatible con arreglos de longitud variable, entonces usted necesita para hacer algo diferente. Si usted necesita todos los elementos para ser asignado en un fragmento contiguo (como una matriz regular), a continuación, puede asignar la memoria como una 1D array, y calcular una 1D offset:

    size_t rows, cols;
    //get rows and columns
    T *ap = malloc(sizeof *ap * rows * cols);
    ...
    ap[i * rows + j] = x;
    ...
    free(ap);

    Si usted no necesita la memoria contiguas, puede seguir dos pasos del método de asignación:

    size_t rows, cols;
    //get rows and cols
    T **ap = malloc(sizeof *ap * rows);
    if (ap)
    {
      size_t i = 0;
      for (i = 0; i < cols; i++)
      {
        ap[i] = malloc(sizeof *ap[i] * cols);
      }
    }
    
    ap[i][j] = x;

    Ya que la asignación fue un proceso de dos pasos, la desasignación también debe ser un proceso de dos pasos:

    for (i = 0; i < cols; i++)
      free(ap[i]);
    free(ap);
    • Sería bueno si el downvoter me diría lo que pienso que me equivoqué.
    • Por favor, dígale a – ¿qué es ap y lo que es T?
    • representa cualquier tipo (int, double, struct foo, etc.). ap es sólo un arbitrario nombre de la variable.
  5. 0

    malloc va a hacer.

     int rows = 20;
     int cols = 20;
     int *array;
    
      array = malloc(rows * cols * sizeof(int));

    Consulte el siguiente artículo de ayuda:-

    http://courses.cs.vt.edu/~cs2704/spring00/mcquain/Notas/4up/Managing2DArrays.pdf

    • Pide la pregunta C. Que fue de C++.
    • Yo sugiero que si usted hace la edición que hizo antes de que usted deje el artículo que había vinculado. A pesar de la sintaxis específicas para C++, todos los conceptos introducidos se mantenga para el método que propones en tu editado respuesta
    • He eliminado como tenía miedo de perder mis puntos. Yo había perdido a muchos de ellos anteriormente también como la gente de aquí son muy específicos de allí las preguntas y no desea explorar.!!! De todos modos Gracias mucho para el impulso de mí
    • sí, me he dado cuenta de que «analness» acerca de LO mismo, pero en su defensa, no es un foro, sino un lugar para obtener respuestas. Un ambiente diferente para acostumbrarse supongo :/
  6. 0

    Aquí es código de trabajo que define una subrutina make_3d_array para asignar un multidimensionales matriz 3D con N1, N2 y N3 elementos en cada dimensión y, a continuación, se rellena con números aleatorios. Puede utilizar la notación de A[i][j][k] para acceder a sus elementos.

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    //Method to allocate a 2D array of floats
    float*** make_3d_array(int nx, int ny, int nz) {
    float*** arr;
    int i,j;
    arr = (float ***) malloc(nx*sizeof(float**));
    for (i = 0; i < nx; i++) {
    arr[i] = (float **) malloc(ny*sizeof(float*));
    for(j = 0; j < ny; j++) {
    arr[i][j] = (float *) malloc(nz * sizeof(float));
    }
    }
    return arr;
    } 
    int main(int argc, char *argv[])
    {
    int i, j, k;
    size_t N1=10,N2=20,N3=5;
    //allocates 3D array
    float ***ran = make_3d_array(N1, N2, N3);
    //initialize pseudo-random number generator
    srand(time(NULL)); 
    //populates the array with random numbers
    for (i = 0; i < N1; i++){
    for (j=0; j<N2; j++) {
    for (k=0; k<N3; k++) {
    ran[i][j][k] = ((float)rand()/(float)(RAND_MAX));
    }
    }
    }
    //prints values
    for (i=0; i<N1; i++) {
    for (j=0; j<N2; j++) {
    for (k=0; k<N3; k++) {
    printf("A[%d][%d][%d] = %f \n", i,j,k,ran[i][j][k]);
    }
    }
    }
    free(ran);
    }
    • Errores: insteast nx y ny tamaños en el bucle de make_3d_array(), tiene que ser de ny y nz. También, los recuerdos de la ran[i][j] y corrió a[i] no se liberan aquí que es muy malo. @rodrigo
  7. -1

    No hay manera de asignar la totalidad de la cosa de una sola vez. En su lugar, cree un array de punteros, entonces, para cada indicador, crear la memoria para él. Por ejemplo:

    int** array;
    array = (int**)malloc(sizeof(int*) * 50);
    for(int i = 0; i < 50; i++)
    array[i] = (int*)malloc(sizeof(int) * 50);

    Por supuesto, también puede declarar la matriz como int* array[50] y tome la primera a malloc, pero el segundo conjunto es necesario para asignar dinámicamente el almacenamiento necesario.

    Es posible hackear una manera de asignar en un solo paso, pero requeriría una búsqueda personalizada de la función, pero la escritura que, en tal manera que siempre el trabajo puede ser molesto. Un ejemplo podría ser L(arr,x,y,max_x) arr[(y)*(max_x) + (x)], entonces malloc un bloque de 50*50 enteros o lo que sea de acceso y uso que L macro, por ejemplo,

    #define L(arr,x,y,max_x) arr[(y)*(max_x) + (x)]
    int dim_x = 50;
    int dim_y = 50;
    int* array = malloc(dim_x*dim_y*sizeof(int));
    int foo = L(array, 4, 6, dim_x);

    Pero que es mucho más desagradable, a menos que usted sabe los efectos de lo que estamos haciendo con la macro de preprocesador.

    • mal, demasiado complicado, moderno C puede hacer mejor, por favor vea mi respuesta.
  8. -1

    //uso de nuevo en lugar de malloc como el uso de malloc lleva a pérdidas de memoria
    `introduzca aquí el código de

        int **adj_list = new int*[rowsize];       
    for(int i = 0; i < rowsize; ++i)    
    {
    adj_list[i] = new int[colsize];
    }
    • Este código es un error de sintaxis en C, tal vez se confunden con algún otro lenguaje
  9. -2
    int rows, columns;
    /* initialize rows and columns to the desired value */
    arr = (int**)malloc(rows*sizeof(int*));
    for(i=0;i<rows;i++)
    {
    arr[i] = (int*)malloc(cols*sizeof(int));
    }
    • demasiado complicado, moderno C puede hacer real multi-dimensiones de las matrices en una sola vez

Dejar respuesta

Please enter your comment!
Please enter your name here