Discutiamo di questo in termini C/C++; ci sono alcune cose aggiuntive da sapere sugli array C# ma non è davvero rilevante al punto.
dato un array di valori interi a 16 bit:
short[5] myArray = {1,2,3,4,5};
cosa è realmente accaduto è che il computer è assegnato un blocco di spazio nella memoria. Questo blocco di memoria è riservato per quell'array, è esattamente la dimensione necessaria per contenere l'array completo (nel nostro caso 16 * 5 == 80 bit == 10 byte) ed è contiguo. Questi fatti sono dati; se qualcuno o nessuno di essi è vero nel proprio ambiente in un dato momento, si rischia generalmente di causare il blocco del programma a causa di una vializzazione di accesso.
Quindi, data questa struttura, ciò che la variabile myArray
è, dietro le quinte, è l'indirizzo di memoria dell'inizio del blocco di memoria. Questo è anche, comodamente, l'inizio del primo elemento. Ogni elemento aggiuntivo è allineato nella memoria subito dopo il primo, in ordine. Il blocco di memoria allocata per myArray
potrebbe essere simile:
00000000000000010000000000000010000000000000001100000000000001000000000000000101
^ ^ ^ ^ ^
myArray([0]) myArray[1] myArray[2] myArray[3] myArray[4]
È considerato un'operazione costante di tempo per accedere ad un indirizzo di memoria e leggere un numero costante di byte. Come nella figura sopra, è possibile ottenere l'indirizzo di memoria per ognuno se si conoscono tre cose; l'inizio del blocco di memoria, la dimensione della memoria di ciascun elemento e l'indice dell'elemento desiderato. Così, quando si chiede myArray[3]
nel codice, tale richiesta è trasformato in un indirizzo di memoria dalla seguente equazione:
myArray[3] == &myArray+sizeof(short)*3;
Così, con un calcolo costante di tempo, avete trovato l'indirizzo di memoria del quarto elemento (indice 3), e con un'altra operazione a tempo costante (o almeno considerata tale, la complessità di accesso effettiva è un dettaglio hardware e abbastanza veloce da non doversene preoccupare) è possibile leggere quella memoria. Questo è, se vi siete mai chiesti, perché gli indici delle raccolte nella maggior parte dei linguaggi in stile C partono da zero; il primo elemento dell'array inizia nella posizione dell'array stesso, senza offset (sizeof (nulla) * 0 == 0)
In C#, ci sono due differenze notevoli. Gli array C# hanno alcune informazioni di intestazione che sono utili per il CLR. L'intestazione viene prima nel blocco di memoria, e la dimensione di questa intestazione è nota e costante, quindi l'equazione indirizzamento ha una sola differenza fondamentale:
myArray[3] == &myArray+headerSize+sizeof(short)*3;
C# non consente di fare riferimento direttamente memoria nel suo gestiti ambiente, ma il runtime stesso utilizzerà qualcosa di simile per eseguire l'accesso alla memoria dall'heap.
La seconda cosa, che è comune anche alla maggior parte dei sapori di C/C++, è che determinati tipi vengono sempre gestiti "per riferimento". Qualsiasi cosa tu debba usare la parola chiave new
da creare è un tipo di riferimento (e ci sono alcuni oggetti, come le stringhe, che sono anche tipi di riferimento anche se sembrano tipi di valori nel codice). Un tipo di riferimento, se istanziato, viene posto in memoria, non si sposta e solitamente non viene copiato. Qualsiasi variabile che rappresenta quell'oggetto è quindi, dietro le quinte, solo l'indirizzo di memoria dell'oggetto in memoria. Gli array sono tipi di riferimento (ricorda che myArray era solo un indirizzo di memoria). Le matrici di tipi di riferimento sono matrici di questi indirizzi di memoria, quindi l'accesso a un oggetto che è un elemento in un array è un processo in due fasi; per prima cosa si calcola l'indirizzo di memoria dell'elemento nell'array e si ottiene quello.Questo è un altro indirizzo di memoria, che è la posizione dell'oggetto reale (o almeno dei suoi dati mutabili, il modo in cui i tipi composti sono strutturati in memoria è un intero altro che può essere un worm). Questa è ancora un'operazione a tempo costante; solo due passi invece di uno.
Sai come i piatti del disco girano intorno e intorno? Beh, la RAM non si muove ;-) –
Sarebbe costante se si potesse saltare immediatamente a casa # 20. Ecco come funziona la RAM. Accesso casuale vs accesso sequenziale. In questo caso casuale si può leggere da qualsiasi posizione di memoria "casuale" senza dover leggere prima la memoria. Lo stesso vale per la scrittura. – SRM