Mapeo de matrices en memoria

Mapeo de matrices en memoria

de Rafael Agustin Castelli Ottati -
Número de respuestas: 2

Buenas, tengo la siguiente confusion respecto a como se mapean las matrices en memoria:
Una matriz es un arreglo de arreglos de tipo T (supongamos de tipo char)
Y un arreglo es un puntero a la direccion del primer elemento

Supongamos que la matriz es M[n][n] con n = 4

Si yo accedo a M[1], me da un puntero que apunta al primer elemento del primer arreglo.
Los siguientes elementos del arreglo van a estar contiguos en memoria, asi como lo estan M[0] y M[1]. Pero M[0] y M[1] estan contiguos en el sentido de que los punteros estan guardados uno al lado del otro, o que los arreglos a los que apuntan estan unos guardados al lado del otro

Supongamos que M[0] esta en la posicion 0x50000, M[1] estara en la posicion 0x50002
Ahora, si M[0] vale 0xD0000, M[1] vale 0xD004 o puede ser que el primer arreglo de la matriz este mapeado
a la direccion 0xD0000 y el arreglo M[1] (es decir el segundo arreglo de la matriz) este mapeado a 0xF1234?

Es decir deberia pensar en una situacion como la de la primera mitad de la imagen o como la segunda? (los ... son para indicar que no necesariamente estan contiguos en memoria)




Saludos,

Rafael

En respuesta a Rafael Agustin Castelli Ottati

Re: Mapeo de matrices en memoria

de Gustavo Brown -

Hola. 

La disposición en memoria de un arreglo bidimensional es como la segunda imagen que pusiste.

Tu confusión seguramente venga de estas frases:

"Una matriz es un arreglo de arreglos de tipo T (supongamos de tipo char)"

Esto es cierto


"Y un arreglo es un puntero a la direccion del primer elemento"

Esto es incorrecto

Un arreglo es una colección de N elementos dispuestos en memoria secuencialmente (uno despues del otro). Cada elemento del arreglo tiene cierto tamaño fijo y uno puede calcular la dirección de comienzo del i-ésimo elemento sumando a la dirección del primer elemento la multiplicación de i por el tamaño de cada elemento del arreglo.

La "definición" de arreglo se puede aplicar "recursivamente" para arreglos multidimensionales.

Entonces por ejemplo supongamos que tenés una matriz bidimensional de caracteres de 5x4 

char M[5][4] ;

lo que estás definiendo es un arreglo de 5 arreglos de 4 caracteres cada uno.

Cada arreglo de 4 caracteres ocupa 4 bytes, entonces sea D la dirección de comienzo del primer arreglo de 4 caracteres, M[0].

Como cada subarreglo contiene 4 caracteres el segundo subarreglo (M[1]) comienza en la dirección D+4*1 = D+4.

El tercer subarreglo (M[2]) comienza en la dirección D + 4*2 = D+8

El cuarto subarreglo (M[3]) comienza en la dirección D + 4*3 = D+12

Y el último subarreglo (M[4]) comienza en la dirección D + 4*4 = D+14

Una vez que accedés a un subarreglo, podes ubicar el elemento j-ésimo de manera similar, sumando a la dirección de comienzo del subarreglo la multiplicación de j por el índice que queres acceder.

Entonces para acceder al caracter M[i][j] se calcula D + 4*i + j


La confusión posiblemente venga de que hayas utilizado una construcción del C particular que es la inicialización de una estructura "puntero a caracter".

Esta definición:

char *string = "hola";

tiene un efecto similar (pero no idéntico) a esta definición:

char string[4] = "hola";

Y en particular la diferencia puede verse cuando uno define un arreglo multidimensional.

No es lo mismo

char matrizA[4][4];

que 

char* matrizB[4];

que 

char ** matrizC;
MatrizA ocupa 16 bytes, 4 bytes por cada uno de los 4 arreglos. Y refleja el segundo dibujo que pusiste.

Supongamos una arquitectura de 32 bits donde los punteros ocupan 4 bytes

MatrizB  ocupa también 16 bytes, 4 bytes por cada puntero de los 4 que se definieron. Cada puntero apunta a la dirección de comienzo de una cadena de caracteres. Si además inicializas cada subarreglo con 4 caracteres entonces el total de memoria que consume sería 16 + 4*4 = 32 bytes. Es el primer dibujo que pusiste

y Matriz C ocupa 4 bytes, que corresponden al puntero donde uno puede almacenar un arreglo de punteros a char. Si además inicializas los punteros con datos para tener una matriz de 4*4 entonces la estrucutra en memoria termina ocupando 4 + 32. El esquema sería similar al de tu primer dibujo pero agregando el puntero al arreglo de punteros a char.

La disposición en memoria de cada una de esas estructuras es distinta. Cuando uno programa en C utilizando los inicializadores de punteros el compilador se encarga de asignar la memoria para cada arreglo y coloca el puntero a la dirección de comienzo del mismo.


Saludos,
  Gustavo