Por que a indexação começa com zero em 'C'?

154

Por que a indexação em uma matriz começa com zero em C e não com 1?

Nitish Pareek
fonte
7
É tudo sobre ponteiros!
medopal 6/09/11
3
possível duplicado de defender base zero matrizes
dmckee --- gatinho ex-moderador
3
Um ponteiro (matriz) é uma direcção da memória e índice é um deslocamento da referida direcção de memória, de modo que o primeiro elemento do ponteiro (matriz) é aquele que compensado é igual a 0.
D33pN16h7
3
@drhirsch porque quando contamos um conjunto de objetos, começamos apontando para um objeto e dizendo "um".
Phoog
1
Os americanos contam os andares (andares) de um edifício a partir de um no térreo; a contagem britânica a partir de (piso térreo) zero, movendo-se para o primeiro andar, em seguida, o segundo andar, etc.
Jonathan Leffler

Respostas:

116

Em C, o nome de uma matriz é essencialmente um ponteiro [mas veja os comentários] , uma referência a um local de memória e, portanto, a expressão array[n]se refere a nelementos de um local de memória distantes do elemento inicial. Isso significa que o índice é usado como um deslocamento. O primeiro elemento da matriz está exatamente contido no local da memória a que a matriz se refere (a 0 elemento de distância), portanto, deve ser indicado como array[0].

Para mais informações:

http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html

Massimiliano Peluso
fonte
20
O nome de uma matriz é o nome da matriz; ao contrário do equívoco comum, matrizes não são ponteiros em nenhum sentido. Uma expressão de matriz (como o nome de um objeto de matriz) é geralmente, mas nem sempre , convertida em um ponteiro para o primeiro elemento. Exemplo: sizeof arrgera o tamanho do objeto da matriz, não o tamanho de um ponteiro.
Keith Thompson
Enquanto você obviamente não reagiu a @ o comentário de KeithThompson, eu gostaria de usar um mais claro ofensa: " Em C, o nome de uma matriz é essencialmente um ponteiro, uma referência a um local de memória " - Não, é não . Pelo menos não em um ponto de vista genérico. Embora sua resposta perfeita responda à pergunta de uma maneira como 0 como o início do índice é importante, a primeira frase está totalmente incorreta. Uma matriz nem sempre decai para um ponteiro para seu primeiro elemento.
RobertS apoia Monica Cellio 01/07
Cite o padrão C, (C18), 6.3.2.1/4: " Exceto quando é o operando do sizeofoperador, ou o &operador unário , ou é uma cadeia de caracteres literal usada para inicializar uma matriz, uma expressão com o tipo" matriz do tipo "é convertido para uma expressão com o tipo" ponteiro para o tipo "que aponta para o elemento inicial do objeto da matriz e não é um lvalue. Se o objeto da matriz tiver classe de armazenamento de registro, o comportamento será indefinido. "
RobertS suporta Monica Cellio 01/07
Além disso, esse decaimento ocorre de maneira mais "implícita" ou "formal" do que o sugerido aqui; não há deterioração para um objeto ponteiro na memória envolvida. Este é o objeto desta pergunta: A matriz do decaimento do ponteiro foi alterada para um objeto de ponteiro? - Edite sua resposta para estar totalmente correta.
RobertS apoia Monica Cellio 01/07
103

Esta pergunta foi publicada há mais de um ano, mas aqui vai ...


Sobre os motivos acima

Embora o artigo de Dijkstra (anteriormente mencionado em uma resposta agora excluída ) faça sentido de uma perspectiva matemática, ele não é tão relevante quando se trata de programação.

A decisão tomada pela especificação de linguagem e pelos projetistas de compiladores é baseada na decisão dos projetistas de sistemas de computador de iniciar a contagem em 0.


A provável razão

Citação de um pedido de paz de Danny Cohen.

Para qualquer base b, os primeiros números inteiros não negativos b ^ N são representados por exatamente N dígitos (incluindo zeros à esquerda) apenas se a numeração começar em 0.

Isso pode ser testado facilmente. Na base 2, pegue 2^3 = 8 o 8º número é:

  • 8 (binário: 1000) se começarmos a contar em 1
  • 7 (binário: 111) se começarmos a contar em 0

111pode ser representado usando 3bits, enquanto 1000exigirá um bit extra (4 bits).


Por que isso é relevante

Os endereços de memória do computador têm 2^Ncélulas endereçadas por Nbits. Agora, se começarmos a contar com 1, as 2^Ncélulas precisarão de N+1linhas de endereço. O bit extra é necessário para acessar exatamente 1 endereço. ( 1000no caso acima.). Outra maneira de resolver isso seria deixar o último endereço inacessível e usar Nlinhas de endereço.

Ambas são soluções subótimas , em comparação com a contagem inicial em 0, que manteria todos os endereços acessíveis, usando exatamente Nas linhas de endereço!


Conclusão

A decisão de começar a contar em 0, desde então, permeou todos os sistemas digitais , incluindo o software executado neles, porque facilita a conversão do código para o que o sistema subjacente pode interpretar. Se não fosse assim, haveria uma operação de conversão desnecessária entre a máquina e o programador, para cada acesso ao array. Facilita a compilação.


Citando o artigo:

insira a descrição da imagem aqui

Anirudh Ramanathan
fonte
2
E se eles tivessem acabado de remover o bit 0 .. então o número 8ª ainda seria 111 ...
DanMatlin
2
Você está realmente sugerindo a modificação da aritmética básica para ajustá-la? Você não acha que o que temos hoje é uma solução muito melhor?
Anirudh Ramanathan
Anos depois, meus 2 cnt valem. Na minha experiência (~ 35 anos de programação), o módulo ou operação de adição modular de uma forma ou de outra surge surpreendentemente com frequência. Com base zero, a próxima sequência é (i + 1)% n, mas com a base 1 vem (i-1)% n) +1, então acho que a base 0 é a preferida. Isso surge em matemática e programação com bastante frequência. Talvez seja apenas eu ou o campo em que trabalho.
Nyholku 12/04/19
Apesar de todas as boas razões, acho muito mais simples: a[b]foi implementado como *(a+b)nos primeiros compiladores. Ainda hoje você ainda pode escrever em 2[a]vez de a[2]. Agora, se os índices não começassem em 0, eles a[b]se tornariam *(a+b-1). Isso exigiria 2 adições nas CPUs do tempo em vez de 0, o que significa metade da velocidade. Claramente não é desejável.
Goswin von Brederlow
1
Só porque você quer 8 estados, isso não significa que você deve ter o número 8 neles. Os interruptores de luz em minha casa são felizes para representar "luz sobre", "luz apagada" estados, sem nunca se perguntando por que eles não representam o número 2.
Spyryto
27

Porque 0 é o quão longe o ponteiro está da cabeça da matriz e o primeiro elemento da matriz.

Considerar:

int foo[5] = {1,2,3,4,5};

Para acessar 0, fazemos:

foo[0] 

Mas foo se decompõe em um ponteiro, e o acesso acima tem uma maneira aritmética de ponteiro análogo de acessá-lo

*(foo + 0)

Atualmente, a aritmética dos ponteiros não é usada com tanta frequência. Quando, porém, era uma maneira conveniente de pegar um endereço e afastar X "ints" desse ponto de partida. Claro que se você quiser ficar onde está, basta adicionar 0!

Doug T.
fonte
23

Como o índice baseado em 0 permite ...

array[index]

... para ser implementado como ...

*(array + index)

Se o índice fosse baseado em 1, o compilador precisaria gerar:, *(array + index - 1)e esse "-1" prejudicaria o desempenho.

Branko Dimitrijevic
fonte
4
Voce trouxe um ponto interessante. Isso pode prejudicar o desempenho. Mas o desempenho atingido será significativo para justificar o uso de 0 como índice inicial? Eu duvido.
Nome Sobrenome
3
@FirstNameLastName Os índices com base em 1 não oferecem vantagem sobre os índices com base em 0, mas apresentam desempenho (ligeiramente) pior. Isso justifica índices baseados em 0, não importa quão pequeno seja o ganho. Mesmo se os índices baseados em 1 oferecerem alguma vantagem, é no espírito do C ++ escolher o desempenho em vez da conveniência. Às vezes, o C ++ é usado em contextos em que todo o último desempenho importa, e essas coisas "pequenas" podem ser adicionadas rapidamente.
Branko Dimitrijevic
Sim, entendo que pequenas coisas podem se acumular e às vezes se tornar uma grande coisa. Por exemplo, US $ 1 por ano não é muito dinheiro. Mas, se 2 bilhões de pessoas doarem, podemos fazer muito bem à humanidade. Estou procurando um exemplo semelhante na codificação que pode causar desempenho ruim.
Nome Sobrenome
2
Em vez de subtrair 1, você deve usar o endereço da matriz-1 como o endereço base. Foi o que fizemos em um compilador que eu trabalhei uma vez. Isso elimina a subtração do tempo de execução. Quando você está escrevendo um compilador, essas instruções extras são muito importantes. O compilador será usado para gerar milhares de programas, cada um dos quais pode ser usado milhares de vezes, e essa instrução extra 1 poderá ocorrer em várias linhas dentro de um loop n quadrado. Pode adicionar bilhões de ciclos desperdiçados.
progrmr
Não, isso não prejudicará o desempenho depois de compilado, ele adicionará apenas um pequeno tempo de compilação, porque no final será traduzido para o código da máquina.
Hassaan Akbar
12

Porque tornou o compilador e o vinculador mais simples (mais fáceis de escrever).

Referência :

"... Fazer referência à memória por um endereço e um deslocamento é representado diretamente no hardware em praticamente todas as arquiteturas de computadores; portanto, esse detalhe de design em C facilita a compilação"

e

"... isso facilita a implementação ..."

progrmr
fonte
1
+1 Não sei por que os votos negativos. Embora não responda diretamente à pergunta, a indexação baseada em 0 não é natural para pessoas ou matemáticos - a única razão para isso é porque a implementação é logicamente consistente (simples).
phkahler
4
@phkahler: o erro está nos autores e idiomas que chamam índices de matriz como índices; se você pensar nisso como um deslocamento, a base de 0 também se tornará natural para os leigos. Considere o relógio, o primeiro minuto é escrito como 00:00, não 00:01, não é?
Lie Ryan
3
+1 - esta é provavelmente a resposta mais correta. C é anterior ao jornal Djikistras e foi um dos primeiros idiomas "iniciar em 0". C começou a vida "como um montador de alto nível" e é provável que a K&R desejasse se aproximar da maneira como era feito no montador, onde normalmente você teria um endereço base mais um deslocamento começando em zero.
James Anderson
Eu pensei que a pergunta era por que 0 baseado foi usado, não o que é melhor.
progrmr
2
Não vou diminuir o voto, mas como o progrmr comentou acima da base, pode ser resolvido ajustando o endereço das matrizes, portanto, independentemente do tempo de execução da base, é o mesmo e isso é trivial para implementar no compilador ou intérprete, para que não seja realmente uma implementação mais simples . Testemunha Pascal, onde você pode usar qualquer intervalo para indexar IIRC, tem sido 25 anos;)
nyholku
5

O índice da matriz sempre começa com zero. Vamos supor que o endereço base seja 2000. Agora arr[i] = *(arr+i). Agora if i= 0, isso significa que *(2000+0) é igual ao endereço base ou endereço do primeiro elemento na matriz. esse índice é tratado como deslocamento, portanto, o índice de bydeafault começa do zero.

Amit Prakash
fonte
5

Pela mesma razão que, quando é quarta-feira e alguém pergunta quantos dias até quarta-feira, você diz 0 em vez de 1 e que quando é quarta-feira e alguém pergunta quantos dias até quinta-feira, você diz 1 em vez de 2.

R .. GitHub PARE DE AJUDAR O GELO
fonte
6
Sua resposta parece apenas uma questão de opinião.
heltonbiker
6
Bem, é o que faz a adição de índices / compensações funcionar. Por exemplo, se "hoje" é 0 e "amanhã" é 1, "amanhã é amanhã" é 1 + 1 = 2. Mas se "hoje" é 1 e "amanhã" é 2, "amanhã é amanhã" não é 2 + 2. Nas matrizes, esse fenômeno ocorre sempre que você deseja considerar um subintervalo de uma matriz como uma matriz por si só.
R .. GitHub Pare de ajudar o gelo
7
Chamar uma coleção de 3 coisas "3 coisas" e numerá-las 1,2,3 não é uma deficiência. Numerá-los com um deslocamento do primeiro não é natural, mesmo em matemática. A única vez que você indexa do zero em matemática é quando deseja incluir algo como a zero-ésima potência (termo constante) em um polinômio.
phkahler
9
Re: "Numerar matrizes começando com 1 em vez de 0 é para pessoas com uma deficiência severa de pensamento matemático". Minha edição do "Introduction to Algorithms" do CLR usa indexação de matriz baseada em 1; Eu não acho que os autores tenham uma deficiência no pensamento matemático.
RexE
Não, eu diria que o sétimo está no índice 6, ou 6 posições longe do primeiro.
R .. GitHub Pare de ajudar o gelo
2

A explicação mais elegante que li para numeração com base em zero é uma observação de que os valores não são armazenados nos locais marcados na linha numérica, mas nos espaços entre eles. O primeiro item é armazenado entre zero e um, o próximo entre um e dois, etc. O enésimo item é armazenado entre N-1 e N. Um intervalo de itens pode ser descrito usando os números de ambos os lados. Os itens individuais são descritos por convenção, usando os números abaixo. Se alguém recebe um intervalo (X, Y), identificar números individuais usando o número abaixo significa que é possível identificar o primeiro item sem usar aritmética (é o item X), mas é preciso subtrair um de Y para identificar o último item (Y -1). A identificação de itens usando o número acima facilitaria a identificação do último item em um intervalo (seria o item Y),

Embora não seja horrível identificar itens com base no número acima deles, definir o primeiro item no intervalo (X, Y) como sendo o item acima X geralmente funciona mais bem do que defini-lo como o item abaixo (X + 1)

supercat
fonte
1

A razão técnica pode derivar do fato de que o ponteiro para um local de memória de uma matriz é o conteúdo do primeiro elemento da matriz. Se você declarar o ponteiro com um índice de um, os programas normalmente adicionariam esse valor de um ao ponteiro para acessar o conteúdo que não é o que você deseja, é claro.

Roubar
fonte
1

Tente acessar uma tela de pixel usando as coordenadas X, Y em uma matriz baseada em 1. A fórmula é totalmente complexa. Por que é complexo? Como você acaba convertendo as cordas X, Y em um número, o deslocamento. Por que você precisa converter X, Y em um deslocamento? Porque é assim que a memória é organizada dentro dos computadores, como um fluxo contínuo de células de memória (matrizes). Como os computadores lidam com as células da matriz? Usando deslocamentos (deslocamentos da primeira célula, um modelo de indexação baseado em zero).

Portanto, em algum momento do código, você precisa (ou o compilador precisa) converter a fórmula de 1 base em uma fórmula de 0 porque é assim que os computadores lidam com a memória.

Gianluca Ghettini
fonte
1

Suponha que desejemos criar uma matriz de tamanho 5
int array [5] = [2,3,5,9,8]

deixe o primeiro elemento da matriz apontar para o local 100

e consideremos que a indexação começa em 1 e não em 0.

agora temos que encontrar a localização do 1º elemento com a ajuda do índice
(lembre-se de que a localização do 1º elemento é 100),

pois o tamanho de um número inteiro é de 4 bits,
portanto -> considerando o índice 1, a posição seria do
tamanho do índice (1) * tamanho do número inteiro (4) = 4,
então a posição real que ele nos mostrará é

100 + 4 = 104

o que não é verdade porque o local inicial era 100.
ele deveria estar apontando para 100 e não para 104
isso está errado

agora, suponha que tenhamos retirado a indexação de 0,
então a
posição do 1º elemento deve ser o
tamanho do índice (0) * tamanho do número inteiro (4) = 0,

portanto -> a
localização do 1º elemento é 100 + 0 = 100

e essa foi a localização real do elemento;
é por isso que a indexação começa em 0;

Espero que isso esclareça seu ponto de vista.

sahil singh
fonte
1

Eu sou de um fundo Java. Apresentei resposta a esta pergunta no diagrama abaixo, que escrevi em um pedaço de papel que é auto-explicativo

Etapas principais:

  1. Criando referência
  2. Instanciação da matriz
  3. Alocação de dados para matriz

  • Observe também quando o array é instanciado .... Zero é alocado para todos os blocos por padrão até atribuirmos valor a ele
  • A matriz começa com zero porque o primeiro endereço estará apontando para a referência (i: e - X102 + 0 na imagem)

insira a descrição da imagem aqui

Nota : Os blocos mostrados na imagem são representados na memória

Devrath
fonte
0

Antes de tudo, você precisa saber que matrizes são consideradas internamente como ponteiros porque o "nome da matriz em si contém o endereço do primeiro elemento da matriz"

ex. int arr[2] = {5,4};

considere que a matriz começa no endereço 100, portanto, o primeiro elemento do elemento estará no endereço 100 e o segundo estará em 104 agora, considere que, se o índice da matriz começar em 1, então

arr[1]:-

isso pode ser escrito na expressão ponteiros como esta-

 arr[1] = *(arr + 1 * (size of single element of array));

considere o tamanho de int é 4 bytes, agora,

arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);

como sabemos o nome da matriz contém o endereço do seu primeiro elemento, então arr = 100 agora,

arr[1] = *(100 + 4);
arr[1] = *(104);

que dá,

arr[1] = 4;

por causa dessa expressão, não podemos acessar o elemento no endereço 100, que é o primeiro elemento oficial,

Agora considere o índice da matriz começa em 0, então

arr[0]:-

isso será resolvido como

arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);

agora, sabemos que o nome da matriz contém o endereço do seu primeiro elemento,

arr[0] = *(100);

o que dá o resultado correto

arr[0] = 5;

portanto, o índice de matriz sempre começa de 0 em c.

referência: todos os detalhes estão escritos no livro "A linguagem de programação C de brian kerninghan e dennis ritchie"

akshay chaudhari
fonte
0

Na matriz, o índice indica a distância do elemento inicial. Portanto, o primeiro elemento está a 0 distância do elemento inicial. Então, é por isso que a matriz começa em 0.

Rishi Raj Tandon
fonte
0

Isso ocorre porque ele addresstem que apontar para a direita elementna matriz. Vamos assumir a matriz abaixo:

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

Vamos agora considerar o início do endereço 12e o tamanho do elementser 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

Se fosse não zero-based , tecnicamente nosso primeiro endereço elemento na arrayseria 16o que é errado, pois de localização é 12.

Thalaivar
fonte
-2

O nome da matriz é um ponteiro constante que aponta para o endereço base. Quando você usa arr [i] o compilador a manipula como * (arr + i). Como o intervalo int é -128 a 127, o compilador pensa que -128 a -1 são números negativos e 0 a 128 são números positivos. Portanto, o índice da matriz sempre começa com zero.

Niks
fonte
1
O que você quer dizer com 'int range is -128 to 127' ? É intnecessário um tipo para oferecer suporte a pelo menos um intervalo de 16 bits e, na maioria dos sistemas hoje em dia, suporta 32 bits. Eu acho que sua lógica é falha e sua resposta realmente não melhora nas outras respostas já fornecidas por outras pessoas. Sugiro excluir isso.
Jonathan Leffler