Perché l'indicizzazione in un array inizia con zero in C e non con 1?
Perché l'indicizzazione in un array inizia con zero in C e non con 1?
Risposte:
In C, il nome di un array è essenzialmente un puntatore [ma vedi i commenti] , un riferimento a una posizione di memoria, e quindi l'espressione si array[n]
riferisce a n
elementi di una posizione di memoria lontani dall'elemento iniziale. Ciò significa che l'indice viene utilizzato come offset. Il primo elemento dell'array è esattamente contenuto nella posizione di memoria a cui fa riferimento l'array (a 0 elementi di distanza), quindi dovrebbe essere indicato come array[0]
.
Per maggiori informazioni:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
sizeof arr
restituisce la dimensione dell'oggetto array, non la dimensione di un puntatore.
sizeof
dell'operatore, o l' &
operatore unario , o è una stringa letterale utilizzata per inizializzare un array, un'espressione che ha tipo" array di tipo "viene convertito in un'espressione con tipo" puntatore a tipo "che punta all'elemento iniziale dell'oggetto array e non è un valore. Se l'oggetto array ha una classe di archiviazione del registro, il comportamento non è definito. "
Questa domanda è stata pubblicata oltre un anno fa, ma qui va ...
Mentre l'articolo di Dijkstra (precedentemente menzionato in una risposta ora cancellata ) ha senso da una prospettiva matematica, non è altrettanto rilevante quando si tratta di programmazione.
La decisione presa dalle specifiche del linguaggio e dai progettisti di compilatori si basa sulla decisione presa dai progettisti di sistemi informatici di iniziare a contare da 0.
Citando un appello per la pace di Danny Cohen.
Per ogni base b, i primi interi non negativi b ^ N sono rappresentati da esattamente N cifre (inclusi gli zeri iniziali) solo se la numerazione inizia da 0.
Questo può essere testato abbastanza facilmente. In base-2, prendi 2^3 = 8
L'ottavo numero è:
111
può essere rappresentato usando i 3
bit, mentre 1000
richiederà un bit in più (4 bit).
Gli indirizzi di memoria del computer hanno 2^N
celle indirizzate da N
bit. Ora se iniziamo a contare da 1, le 2^N
celle avrebbero bisogno di N+1
linee di indirizzo. Il bit extra è necessario per accedere esattamente a 1 indirizzo. ( 1000
nel caso sopra.). Un altro modo per risolverlo sarebbe lasciare inaccessibile l'ultimo indirizzo e utilizzare le N
righe degli indirizzi.
Entrambe sono soluzioni non ottimali , rispetto al conteggio iniziale a 0, che manterrebbe accessibili tutti gli indirizzi, usando esattamente le N
righe degli indirizzi!
La decisione di iniziare a contare 0
da allora ha permeato tutti i sistemi digitali , incluso il software in esecuzione su di essi, perché rende più semplice la conversione del codice in ciò che il sistema sottostante può interpretare. Se così non fosse, ci sarebbe un'operazione di traduzione non necessaria tra la macchina e il programmatore, per ogni accesso all'array. Rende la compilazione più semplice.
Citando dal documento:
a[b]
stato implementato come *(a+b)
nei primi compilatori. Ancora oggi puoi ancora scrivere 2[a]
invece di a[2]
. Ora se gli indici non iniziano da 0, a[b]
si trasformerebbero in *(a+b-1)
. Ciò avrebbe richiesto 2 aggiunte sulle CPU del tempo anziché 0, il che significa metà della velocità. Chiaramente non desiderabile.
Perché 0 è quanto lontano dal puntatore alla testa dell'array al primo elemento dell'array.
Tener conto di:
int foo[5] = {1,2,3,4,5};
Per accedere a 0 facciamo:
foo[0]
Ma foo si decompone in un puntatore e l'accesso sopra ha un modo aritmetico di puntatore analogo per accedervi
*(foo + 0)
Al giorno d'oggi l'aritmetica del puntatore non viene utilizzata così frequentemente. Molto tempo fa, però, era un modo conveniente per prendere un indirizzo e spostare X "ints" lontano da quel punto di partenza. Ovviamente se volevi semplicemente rimanere dove sei, aggiungi solo 0!
Perché l'indice basato su 0 consente ...
array[index]
... da implementare come ...
*(array + index)
Se l'indice fosse basato su 1, il compilatore dovrebbe generare:, *(array + index - 1)
e questo "-1" danneggerebbe le prestazioni.
Perché ha reso il compilatore e il linker più semplici (più facili da scrivere).
"... Fare riferimento alla memoria tramite un indirizzo e un offset è rappresentato direttamente nell'hardware praticamente su tutte le architetture di computer, quindi questo dettaglio di progettazione in C semplifica la compilazione"
e
"... questo rende l'implementazione più semplice ..."
L'indice di array inizia sempre con zero. Supponiamo che l'indirizzo di base sia 2000. Ora arr[i] = *(arr+i)
. Ora if i= 0
, questo significa *(2000+0
) è uguale all'indirizzo di base o all'indirizzo del primo elemento nell'array. questo indice è trattato come offset, quindi l'indice predefinito è zero.
Per lo stesso motivo che, quando è mercoledì e qualcuno ti chiede quanti giorni fino a mercoledì, dici 0 anziché 1, e che quando è mercoledì e qualcuno ti chiede quanti giorni fino a giovedì, dici 1 anziché 2.
La spiegazione più elegante che ho letto per la numerazione in base zero è un'osservazione che i valori non sono memorizzati nei punti contrassegnati sulla linea numerica, ma piuttosto negli spazi tra loro. Il primo elemento viene memorizzato tra zero e uno, il successivo tra uno e due, ecc. L'ennesimo elemento viene memorizzato tra N-1 e N. Un intervallo di elementi può essere descritto utilizzando i numeri su entrambi i lati. I singoli articoli sono per convenzione descritti usando i numeri sottostanti. Se viene assegnato un intervallo (X, Y), l'identificazione di singoli numeri utilizzando il numero riportato di seguito significa che è possibile identificare il primo elemento senza utilizzare alcun calcolo aritmetico (è l'elemento X) ma è necessario sottrarre uno da Y per identificare l'ultimo elemento (Y -1). Identificare gli articoli utilizzando il numero sopra renderebbe più semplice identificare l'ultimo articolo in un intervallo (sarebbe l'articolo Y),
Anche se non sarebbe orribile identificare gli elementi in base al numero sopra di loro, definire il primo oggetto nell'intervallo (X, Y) come quello sopra X generalmente funziona più bene che definirlo come quello sotto (X + 1).
Il motivo tecnico potrebbe derivare dal fatto che il puntatore a una posizione di memoria di un array è il contenuto del primo elemento dell'array. Se dichiarate il puntatore con un indice di uno, i programmi normalmente aggiungerebbero quel valore di uno al puntatore per accedere al contenuto che non è quello che volete, ovviamente.
Prova ad accedere a uno schermo pixel usando le coordinate X, Y su una matrice basata su 1. La formula è assolutamente complessa. Perché è complesso Perché finisci per convertire le coordinate X, Y in un numero, l'offset. Perché è necessario convertire X, Y in un offset? Perché è così che la memoria è organizzata all'interno dei computer, come un flusso continuo di celle di memoria (array). Come i computer gestiscono le celle di array? Utilizzo degli offset (spostamenti dalla prima cella, un modello di indicizzazione a base zero).
Quindi a un certo punto del codice è necessario (o è necessario il compilatore) per convertire la formula a base 1 in una formula a base 0 perché è così che i computer gestiscono la memoria.
Supponiamo di voler creare un array di dimensione 5
int array [5] = [2,3,5,9,8]
lasciare che il primo elemento dell'array sia puntato nella posizione 100
e consideriamo che l'indicizzazione inizia da 1 non da 0.
ora dobbiamo trovare la posizione del primo elemento con l'aiuto dell'indice
(ricordate che la posizione del 1 ° elemento è 100)
poiché la dimensione di un numero intero è di 4 bit
quindi -> considerando l'indice 1 la posizione sarebbe
dimensione of index (1) * size of integer (4) = 4,
quindi la posizione effettiva che ci mostrerà è
100 + 4 = 104
il che non è vero perché la posizione iniziale era a 100.
dovrebbe puntare a 100 non a 104
questo è sbagliato
ora supponiamo che abbiamo preso l'indicizzazione da 0
quindi la
posizione del 1 ° elemento dovrebbe essere la
dimensione dell'indice (0) * dimensione dell'intero (4) = 0
quindi -> la
posizione del primo elemento è 100 + 0 = 100
e quella era la posizione effettiva dell'elemento,
ecco perché l'indicizzazione inizia da 0;
Spero che chiarisca il tuo punto.
Vengo da uno sfondo Java. Ho presentato la risposta a questa domanda nel diagramma sotto il quale ho scritto in un pezzo di carta che si spiega da sé
Passaggi principali:
Nota : i blocchi mostrati nell'immagine rappresentano la memoria
prima di tutto devi sapere che gli array sono considerati internamente come puntatori perché il "nome dell'array stesso contiene l'indirizzo del primo elemento dell'array"
ex. int arr[2] = {5,4};
considera che l'array inizia all'indirizzo 100, quindi il primo elemento sarà all'indirizzo 100 e il secondo sarà ora 104, considera che se l'indice dell'array inizia da 1, quindi
arr[1]:-
questo può essere scritto nell'espressione puntatori come questo-
arr[1] = *(arr + 1 * (size of single element of array));
considera che la dimensione di int è 4byte, ora,
arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);
come sappiamo il nome dell'array contiene l'indirizzo del suo primo elemento, quindi arr = 100 ora,
arr[1] = *(100 + 4);
arr[1] = *(104);
che dà,
arr[1] = 4;
a causa di questa espressione non siamo in grado di accedere all'elemento all'indirizzo 100 che è il primo elemento ufficiale,
ora considera l'indice di array che inizia da 0, quindi
arr[0]:-
questo sarà risolto come
arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);
ora sappiamo che il nome dell'array contiene l'indirizzo del suo primo elemento quindi,
arr[0] = *(100);
che dà il risultato corretto
arr[0] = 5;
pertanto l'indice di array inizia sempre da 0 in c.
riferimento: tutti i dettagli sono scritti nel libro "Il linguaggio di programmazione C di brian kerninghan e dennis ritchie"
Nell'array, l'indice indica la distanza dall'elemento iniziale. Quindi, il primo elemento è a 0 distanza dall'elemento iniziale. Ecco perché l'array inizia da 0.
È perché address
deve puntare a destra element
nell'array. Supponiamo che l'array seguente:
let arr = [10, 20, 40, 60];
Consideriamo ora l'inizio dell'essere indirizzo 12
e la dimensione del element
BE 4 bytes
.
address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24
In caso contrario zero-based
, tecnicamente il nostro primo indirizzo di elemento in array
sarebbe 16
che è sbagliato come è la sua posizione 12
.
Il nome della matrice è un puntatore costante che punta all'indirizzo di base. Quando si utilizza arr [i] il compilatore lo manipola come * (arr + i). Poiché l'intervallo int è compreso tra -128 e 127, il compilatore pensa che tra -128 e -1 siano i numeri negativi e da 0 a 128 sono numeri positivi, quindi l'indice di array inizia sempre con zero.
int
necessario un tipo per supportare un intervallo di almeno 16 bit e, nella maggior parte dei sistemi, in questi giorni supporta 32 bit. Penso che la tua logica sia difettosa e la tua risposta in realtà non migliora rispetto alle altre risposte già fornite da altre persone. Suggerisco di cancellarlo.