Perché l'indicizzazione inizia con zero in 'C'?


154

Perché l'indicizzazione in un array inizia con zero in C e non con 1?


7
Si tratta solo di puntatori!
medopal,

3
possibile duplicato di array
dmckee --- ex-moderator kitten

3
Un puntatore (matrice) è una direzione della memoria e l'indice è un offset di quella direzione della memoria, quindi il primo elemento del puntatore (matrice) è quello che ha un offset pari a 0.
D33pN16h7

3
@drhirsch perché quando contiamo un insieme di oggetti, iniziamo indicando un oggetto e dicendo "uno".
phoog,

1
Gli americani contano i piani (piani) di un edificio da uno al piano terra; gli inglesi contano da zero (piano terra), salendo al primo piano, poi al secondo piano, ecc.
Jonathan Leffler,

Risposte:


116

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 nelementi 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


20
Il nome di un array è il nome dell'array; contrariamente al malinteso comune, le matrici non sono in alcun senso indicazioni. Un'espressione di matrice (come il nome di un oggetto di matrice) viene solitamente, ma non sempre , convertita in un puntatore al primo elemento. Esempio: sizeof arrrestituisce la dimensione dell'oggetto array, non la dimensione di un puntatore.
Keith Thompson,

Mentre ovviamente non ha reagito a @ commento di KeithThompson, vorrei si utilizza un altro corso di reato: " In C, il nome di un array è essenzialmente un puntatore, un riferimento a una posizione di memoria " - No, è non è . Almeno non da un punto di vista generico. Mentre la tua risposta perfetta risponde alla domanda in un modo in cui 0 come inizio dell'indice è importante, la prima frase è semplicemente errata. Un array non decade sempre in un puntatore al suo primo elemento.
RobertS supporta Monica Cellio il

Citazione dallo standard C, (C18), 6.3.2.1/4: " Tranne quando è l'operando sizeofdell'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. "
RobertS supporta Monica Cellio

Anche questo decadimento avviene in modo più "implicito" o "formale" di quanto suggerito qui; non vi è alcun decadimento di un oggetto puntatore nella memoria coinvolto. Questo è l'oggetto di questa domanda: l'array per il decadimento del puntatore è cambiato in un oggetto puntatore? - Modifica la tua risposta per essere completamente corretta.
RobertS supporta Monica Cellio il

103

Questa domanda è stata pubblicata oltre un anno fa, ma qui va ...


Sui motivi di cui sopra

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.


La probabile ragione

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 è:

  • 8 (binario: 1000) se iniziamo a contare da 1
  • 7 (binario: 111) se iniziamo a contare da 0

111può essere rappresentato usando i 3bit, mentre 1000richiederà un bit in più (4 bit).


Perché questo è rilevante

Gli indirizzi di memoria del computer hanno 2^Ncelle indirizzate da Nbit. Ora se iniziamo a contare da 1, le 2^Ncelle avrebbero bisogno di N+1linee di indirizzo. Il bit extra è necessario per accedere esattamente a 1 indirizzo. ( 1000nel caso sopra.). Un altro modo per risolverlo sarebbe lasciare inaccessibile l'ultimo indirizzo e utilizzare le Nrighe degli indirizzi.

Entrambe sono soluzioni non ottimali , rispetto al conteggio iniziale a 0, che manterrebbe accessibili tutti gli indirizzi, usando esattamente le Nrighe degli indirizzi!


Conclusione

La decisione di iniziare a contare 0da 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:

inserisci qui la descrizione dell'immagine


2
E se avessero appena rimosso il bit 0 .. allora l'ottavo numero sarebbe ancora 111 ...
DanMatlin

2
Stai davvero suggerendo una modifica dell'aritmetica di base per adattarla? Non pensi che quello che abbiamo oggi sia una soluzione molto migliore?
Anirudh Ramanathan,

Anni dopo il mio valore di 2 cnt. Nella mia esperienza (~ 35 anni di programmazione) il modulo o l'operazione di aggiunta modulare in una forma o nell'altra si presenta sorprendentemente spesso. Con zero base il successivo in sequenza è (i + 1)% n ma con base 1 arriva (i-1)% n) +1, quindi penso che sia preferito 0 basato. Ciò si manifesta in matematica e programmazione abbastanza spesso. Forse sono solo io o il campo in cui lavoro.
nyholku,

Mentre tutte le buone ragioni penso che sia molto più semplice: è 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.
Goswin von Brederlow,

1
Solo perché vuoi 8 stati, non significa che devi avere il numero 8 in essi. Gli interruttori della luce nella mia casa sono felici di rappresentare gli stati "luce accesa", "luce spenta", senza mai chiedersi perché non rappresentano il numero 2.
Spyryto

27

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!


23

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.


4
Hai sollevato un punto interessante. Può danneggiare le prestazioni. Ma il colpo di performance sarà significativo per giustificare l'uso di 0 come indice iniziale? Ne dubito.
Nome Cognome

3
@FirstNameLastName Gli indici basati su 1 non offrono alcun vantaggio sugli indici basati su 0, ma hanno prestazioni (leggermente) peggiori. Ciò giustifica gli indici basati su 0, non importa quanto "piccolo" sia il guadagno. Anche se gli indici basati su 1 offrivano qualche vantaggio, è nello spirito del C ++ scegliere le prestazioni piuttosto che la convenienza. Il C ++ viene talvolta utilizzato in contesti in cui ogni ultimo bit di prestazioni è importante e queste "piccole" cose possono rapidamente sommarsi.
Branko Dimitrijevic,

Sì, capisco che le piccole cose possono sommarsi e talvolta diventare una grande cosa. Ad esempio, $ 1 all'anno non sono molti soldi. Ma se 2 miliardi di persone lo donano, allora possiamo fare molto bene all'umanità. Sto cercando un esempio simile nella codifica che potrebbe causare scarse prestazioni.
Nome Cognome

2
Invece di sottrarre 1, è necessario utilizzare l'indirizzo dell'array-1 come indirizzo di base. Quello che abbiamo fatto in un compilatore su cui ho lavorato una volta. Ciò elimina la sottrazione di runtime. Quando scrivi un compilatore, quelle istruzioni extra contano molto. Il compilatore verrà utilizzato per generare migliaia di programmi, ognuno dei quali può essere utilizzato migliaia di volte, e quell'istruzione aggiuntiva 1 può verificarsi in più righe all'interno di un ciclo n quadrato. Può aggiungere fino a miliardi di cicli sprecati.
progr

No, non danneggerà le prestazioni una volta compilato, aggiungerà solo un piccolo tempo di costruzione perché alla fine verrà tradotto in codice macchina e danneggerà solo i progettisti del compilatore.
Hassaan Akbar,

12

Perché ha reso il compilatore e il linker più semplici (più facili da scrivere).

Riferimento :

"... 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 ..."


1
+1 Non so perché il voto negativo. Sebbene non risponda direttamente alla domanda, l'indicizzazione basata su 0 non è naturale per persone o matematici - l'unica ragione per cui è stata fatta è perché l'implementazione è logicamente coerente (semplice).
Phkahler,

4
@phkahler: l'errore è negli autori e nelle lingue che chiamano indici di array come indici; se lo consideri come un offset, allora la base 0 diventa naturale anche per i laici. Considera l'orologio, il primo minuto è scritto come 00:00, non 00:01 non è vero?
Lie Ryan,

3
+1: questa è probabilmente la risposta più corretta. C ha preceduto il giornale Djikistras ed è stata una delle prime lingue "inizio a 0". C ha iniziato la sua vita "come un assemblatore di alto livello" ed è probabile che K&R volesse attenersi al modo in cui è stato fatto nell'assemblatore dove normalmente avresti un indirizzo base più un offset che inizia da zero.
James Anderson,

Ho pensato che la domanda fosse perché fosse usato lo 0, non quale fosse meglio.
progr

2
Non voglio sottovalutare, ma come può essere curato progrmr commentato sopra la base regolando l'indirizzo degli array, quindi indipendentemente dal tempo di esecuzione della base è lo stesso e questo è banale da implementare nel compilatore o nell'interprete, quindi non rende davvero più semplice l'implementazione . Testimone Pascal dove è possibile utilizzare qualsiasi intervallo per l'indicizzazione IIRC, sono passati 25 anni;)
nyholku

5

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.


5

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.


6
La tua risposta sembra solo una questione di opinione.
Heltonbiker

6
Bene, è ciò che fa funzionare l'aggiunta di indici / offset. Ad esempio, se "oggi" è 0 e "domani" è 1, "domani è domani" è 1 + 1 = 2. Ma se "oggi" è 1 e "domani" è 2, "domani è domani" non è 2 + 2. Negli array, questo fenomeno si verifica ogni volta che si desidera considerare un sottoinsieme di un array come un array a sé stante.
R .. GitHub smette di aiutare ICE il

7
Chiamare una raccolta di 3 cose "3 cose" e numerarle 1,2,3 non è un difetto. Numerarli con un offset dal primo non è naturale nemmeno in matematica. L'unica volta che indicizzi da zero in matematica è quando vuoi includere qualcosa come la potenza zero (termine costante) in un polinomio.
Phkahler,

9
Ri: "Le matrici di numerazione che iniziano con 1 anziché con 0 sono per le persone con una grave carenza del pensiero matematico". La mia edizione di "Introduzione agli algoritmi" di CLR utilizza l'indicizzazione di array basata su 1; Non penso che gli autori abbiano una carenza nel pensiero matematico.
RexE,

No, direi che il settimo è all'indice 6, o 6 posizioni di distanza dal primo.
R .. GitHub FERMA AIUTANDO ICE

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).


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.


1

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.


1

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.


1

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:

  1. Creazione di riferimento
  2. Istanziazione di array
  3. Allocazione dei dati all'array

  • Nota anche quando l'array è appena istanziato .... Zero è allocato su tutti i blocchi per impostazione predefinita fino a quando non assegniamo un valore per esso
  • La matrice inizia con zero perché il primo indirizzo punterà al riferimento (i: e - X102 + 0 nell'immagine)

inserisci qui la descrizione dell'immagine

Nota : i blocchi mostrati nell'immagine rappresentano la memoria


0

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"


0

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.


0

È perché addressdeve puntare a destra elementnell'array. Supponiamo che l'array seguente:

let arr = [10, 20, 40, 60]; 

Consideriamo ora l'inizio dell'essere indirizzo 12e la dimensione del elementBE 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 arraysarebbe 16che è sbagliato come è la sua posizione 12.


-2

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.


1
Cosa intendi con "int range è compreso tra -128 e 127" ? È intnecessario 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.
Jonathan Leffler il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.