una resueltos recorrer matriz matrices hacer ejercicios como bidimensionales bidimensional arreglos array c arrays multidimensional-array malloc allocation

recorrer - matrices en c# ejercicios resueltos



¿Una forma extraña de asignar una matriz bidimensional? (3)

Esta es la forma típica en que debe asignar matrices 2D dinámicamente.

  • e es un puntero de matriz a una matriz de tipo double [n+1] .
  • sizeof(*e) por lo tanto, da el tipo del tipo apuntado, que es el tamaño de una matriz double [n+1] .
  • Usted asigna espacio para n+1 tales matrices.
  • Configura el puntero de matriz e para que apunte a la primera matriz de esta matriz de matrices.
  • Esto le permite usar e como e[i][j] para acceder a elementos individuales en la matriz 2D.

Personalmente creo que este estilo es mucho más fácil de leer:

double (*e)[n+1] = malloc( sizeof(double[n+1][n+1]) );

En un proyecto, alguien empujó esta línea:

double (*e)[n+1] = malloc((n+1) * sizeof(*e));

Lo que supuestamente crea una matriz bidimensional de (n + 1) * (n + 1) dobles.

Supuestamente , digo, porque hasta ahora, nadie a quien pregunté podía decirme qué hace exactamente, ni de dónde se originó o por qué debería funcionar (lo que supuestamente funciona, pero todavía no lo estoy comprando).

Quizás me estoy perdiendo algo obvio, pero agradecería que alguien me lo explicara. Porque personalmente, me sentiría mucho mejor si usáramos algo que realmente entendemos.


Este idioma cae naturalmente de la asignación de matriz 1D. Comencemos por asignar una matriz 1D de algún tipo arbitrario T :

T *p = malloc( sizeof *p * N );

Simple, verdad? La expresión *p tiene el tipo T , por lo que sizeof *p da el mismo resultado que sizeof (T) , por lo que estamos asignando suficiente espacio para una matriz de elementos N de T Esto es cierto para cualquier tipo T

Ahora, sustituyamos T con un tipo de matriz como R [10] . Entonces nuestra asignación se convierte

R (*p)[10] = malloc( sizeof *p * N);

La semántica aquí es exactamente la misma que el método de asignación 1D; todo lo que ha cambiado es el tipo de p . En lugar de T * , ahora es R (*)[10] . La expresión *p tiene tipo T que es tipo R [10] , por lo que sizeof *p es equivalente a sizeof (T) que es equivalente a sizeof (R [10]) . Así que estamos asignando suficiente espacio para una matriz de N por 10 elementos de R

Podemos llevar esto aún más lejos si queremos; supongamos que R es en sí mismo un tipo de matriz int [5] . Sustituya eso por R y obtenemos

int (*p)[10][5] = malloc( sizeof *p * N);

El mismo trato: sizeof *p es igual que sizeof (int [10][5]) , y terminamos asignando una porción contigua de memoria lo suficientemente grande como para contener una matriz N por 10 por 5 de int .

Entonces ese es el lado de la asignación; ¿Qué pasa con el lado de acceso?

Recuerde que la operación de subíndice [] se define en términos de aritmética de puntero: a[i] se define como *(a + i) 1 . Por lo tanto, el operador de subíndice [] desreferencia implícitamente un puntero. Si p es un puntero a T , puede acceder al valor señalado ya sea haciendo referencia explícitamente con el operador unario * :

T x = *p;

o usando el operador de subíndice [] :

T x = p[0]; // identical to *p

Por lo tanto, si p apunta al primer elemento de una matriz , puede acceder a cualquier elemento de esa matriz utilizando un subíndice en el puntero p :

T arr[N]; T *p = arr; // expression arr "decays" from type T [N] to T * ... T x = p[i]; // access the i''th element of arr through pointer p

Ahora, hagamos nuevamente nuestra operación de sustitución y reemplacemos T con el tipo de matriz R [10] :

R arr[N][10]; R (*p)[10] = arr; // expression arr "decays" from type R [N][10] to R (*)[10] ... R x = (*p)[i];

Una diferencia inmediatamente aparente; estamos desreferenciando explícitamente p antes de aplicar el operador de subíndice. No queremos subíndice en p , queremos subíndice en lo que p apunta (en este caso, la matriz arr[0] ). Como el unario * tiene una precedencia menor que el operador del subíndice [] , debemos usar paréntesis para agrupar explícitamente p con * . Pero recuerde desde arriba que *p es lo mismo que p[0] , por lo que podemos sustituirlo con

R x = (p[0])[i];

o solo

R x = p[0][i];

Por lo tanto, si p apunta a una matriz 2D, podemos indexar en esa matriz a través de p manera:

R x = p[i][j]; // access the i''th element of arr through pointer p; // each arr[i] is a 10-element array of R

Llevando esto a la misma conclusión que anteriormente y sustituyendo R con int [5] :

int arr[N][10][5]; int (*p)[10][5]; // expression arr "decays" from type int [N][5][10] to int (*)[10][5] ... int x = p[i][j][k];

Esto funciona igual si p apunta a una matriz regular, o si apunta a la memoria asignada a través de malloc .

Este modismo tiene los siguientes beneficios:

  1. Es simple: solo una línea de código, a diferencia del método de asignación gradual

    T **arr = malloc( sizeof *arr * N ); if ( arr ) { for ( size_t i = 0; i < N; i++ ) { arr[i] = malloc( sizeof *arr[i] * M ); } }

  2. Todas las filas de la matriz asignada son * contiguas *, que no es el caso con el método de asignación fragmentado anterior;
  3. Desasignar la matriz es igual de fácil con una sola llamada free . Nuevamente, no es cierto con el método de asignación gradual, donde debe desasignar cada arr[i] antes de poder desasignar arr .

A veces, el método de asignación gradual es preferible, como cuando su montón está muy fragmentado y no puede asignar su memoria como un fragmento contiguo, o si desea asignar una matriz "irregular" donde cada fila puede tener una longitud diferente. Pero en general, este es el mejor camino a seguir.

1. Recuerde que las matrices no son punteros; en cambio, las expresiones de matrices se convierten en expresiones de puntero según sea necesario.


La variable e es un puntero a una matriz de n + 1 elementos de tipo double .

El uso del operador de desreferencia en e le da el tipo base de e que es "matriz de n + 1 elementos de tipo double ".

La llamada malloc simplemente toma el tipo base de e (explicado anteriormente) y obtiene su tamaño, lo multiplica por n + 1 y pasa ese tamaño a la función malloc . Esencialmente asignando una matriz de n + 1 matrices de n + 1 elementos de double .