Discutamos esto en términos de C/C++; hay algunas cosas adicionales para saber acerca de las matrices de C#, pero no es realmente relevante al punto.
Dado un conjunto de valores enteros de 16 bits:
short[5] myArray = {1,2,3,4,5};
Lo que realmente sucedió es que el ordenador ha asignado un bloque de espacio en la memoria. Este bloque de memoria está reservado para esa matriz, es exactamente el tamaño necesario para mantener la matriz completa (en nuestro caso 16 * 5 == 80 bits == 10 bytes), y es contigua. Estos hechos son dados; si alguna o ninguna de ellas es verdadera en su entorno en un momento dado, generalmente corre el riesgo de que su programa se bloquee debido a un acceso vialoation.
Por lo tanto, dada esta estructura, lo que la variable myArray
realmente es, detrás de las escenas, es la dirección de memoria del inicio del bloque de memoria. Esto también es, convenientemente, el comienzo del primer elemento. Cada elemento adicional se alinea en la memoria inmediatamente después del primero, en orden. El bloque de memoria asignada para myArray
podría tener este aspecto:
00000000000000010000000000000010000000000000001100000000000001000000000000000101
^ ^ ^ ^ ^
myArray([0]) myArray[1] myArray[2] myArray[3] myArray[4]
Se considera una operación constante de tiempo para acceder a una dirección de memoria y leer un número constante de bytes. Como en la figura anterior, puede obtener la dirección de memoria para cada uno si conoce tres cosas; el inicio del bloque de memoria, el tamaño de la memoria de cada elemento y el índice del elemento que desea. Por lo tanto, cuando se pide myArray[3]
en su código, esa petición se convierte en una dirección de memoria mediante la siguiente ecuación:
myArray[3] == &myArray+sizeof(short)*3;
Por lo tanto, con un cálculo en tiempo constante, que ha encontrado la dirección de memoria del cuarto elemento (índice 3), y con otra operación de tiempo constante (o al menos así se considera, la complejidad real del acceso es un detalle de hardware y lo suficientemente rápido como para que no le importe) puede leer esa memoria. Esto es, si alguna vez se preguntó, por qué los índices de colecciones en la mayoría de los lenguajes de estilo C comienzan en cero; el primer elemento de la matriz comienza en la ubicación de la matriz en sí, sin desplazamiento (sizeof (cualquier cosa) * 0 == 0)
En C#, hay dos diferencias notables. Las matrices C# tienen información de encabezado que es útil para el CLR. La cabecera es lo primero en el bloque de memoria, y el tamaño de esta cabecera es constante y conocida, por lo que la ecuación de abordar tiene sólo una diferencia clave:
myArray[3] == &myArray+headerSize+sizeof(short)*3;
C# no permite hacer referencia a la memoria directamente en su gestión entorno, pero el tiempo de ejecución en sí utilizará algo como esto para realizar el acceso a memoria fuera del montón.
Lo segundo, que es común para la mayoría de los sabores de C/C++ también, es que ciertos tipos siempre se tratan "por referencia". Todo lo que tiene que usar la palabra clave new
para crear es un tipo de referencia (y hay algunos objetos, como cadenas, que también son tipos de referencia aunque parezcan tipos de valores en el código). Un tipo de referencia, cuando se crea una instancia, se coloca en la memoria, no se mueve y generalmente no se copia. Cualquier variable que represente ese objeto es, por lo tanto, detrás de escena, solo la dirección de memoria del objeto en la memoria. Las matrices son tipos de referencia (recuerde que myArray era solo una dirección de memoria). Las matrices de tipos de referencia son matrices de estas direcciones de memoria, por lo que acceder a un objeto que es un elemento de una matriz es un proceso de dos pasos; primero calcula la dirección de memoria del elemento en la matriz y la obtiene.Esa es otra dirección de memoria, que es la ubicación del objeto real (o al menos sus datos mutables, cómo los tipos compuestos están estructurados en la memoria es un conjunto de otros gusanos). Esta sigue siendo una operación de tiempo constante; solo dos pasos en lugar de uno.
¿Sabes cómo los platos del disco dan vueltas y vueltas? Bueno, la RAM no se mueve ;-) –
Sería constante si pudieras saltar al instante a la casa # 20. Así es como funciona la RAM. Acceso aleatorio frente a acceso secuencial. En este caso, aleatorio significa que puede leer desde cualquier ubicación de memoria "aleatoria" sin tener que leer la memoria anterior. Lo mismo vale para escribir. – SRM