Eu acho que algo está faltando nas outras respostas.
Sim, p[i]
por definição é equivalente a *(p+i)
, o qual (porque a adição é comutativa) é equivalente a *(i+p)
, ao qual (novamente, pela definição do []
operador) é equivalente a i[p]
.
(E array[i]
, em , o nome da matriz é implicitamente convertido em um ponteiro para o primeiro elemento da matriz.)
Mas a comutatividade da adição não é tão óbvia nesse caso.
Quando ambos os operandos são do mesmo tipo, ou mesmo de diferentes tipos numéricos que são promovidos a um tipo comum, comutatividade faz todo o sentido: x + y == y + x
.
Mas, neste caso, estamos falando especificamente sobre aritmética de ponteiros, em que um operando é um ponteiro e o outro é um número inteiro. (Inteiro + inteiro é uma operação diferente, e ponteiro + ponteiro é um disparate.)
A descrição do +
operador da norma C ( N1570 6.5.6) diz:
Além disso, ambos os operandos devem ter um tipo aritmético ou um operando deve ser um ponteiro para um tipo de objeto completo e o outro deve ter um tipo inteiro.
Poderia facilmente ter dito:
Além disso, ambos os operandos devem ter um tipo aritmético ou o
operando esquerdo deve ser um ponteiro para um tipo de objeto completo e o operando direito
deve ter um tipo inteiro.
nesse caso, ambos i + p
e i[p]
seria ilegal.
Em termos de C ++, realmente temos dois conjuntos de +
operadores sobrecarregados , que podem ser descritos livremente como:
pointer operator+(pointer p, integer i);
e
pointer operator+(integer i, pointer p);
dos quais apenas o primeiro é realmente necessário.
Então, por que é assim?
O C ++ herdou essa definição de C, que a obteve de B (a comutatividade da indexação de matriz é explicitamente mencionada na Referência do Usuário de 1972 para B ), que a obteve de BCPL (manual de 1967), que pode muito bem ter sido obtida até idiomas anteriores (CPL? Algol?).
Portanto, a ideia de que a indexação de array é definida em termos de adição, e essa adição, mesmo de ponteiro e número inteiro, é comutativa, remonta há muitas décadas aos idiomas ancestrais de C.
Essas línguas eram muito menos tipificadas do que o C moderno. Em particular, a distinção entre ponteiros e números inteiros era frequentemente ignorada. (Os programadores C iniciais às vezes usavam ponteiros como números inteiros não assinados, antes que a unsigned
palavra - chave fosse adicionada ao idioma.) Portanto, a idéia de tornar a adição não comutativa porque os operandos são de tipos diferentes provavelmente não teria ocorrido aos projetistas dessas linguagens. Se um usuário quiser adicionar duas "coisas", sejam elas números inteiros, ponteiros ou qualquer outra coisa, não cabe ao idioma impedi-lo.
E, ao longo dos anos, qualquer alteração a essa regra quebraria o código existente (embora o padrão ANSI C de 1989 possa ter sido uma boa oportunidade).
Alterar C e / ou C ++ para exigir colocar o ponteiro à esquerda e o número inteiro à direita pode quebrar algum código existente, mas não haveria perda de potência expressiva real.
Portanto, agora temos arr[3]
e 3[arr]
significamos exatamente a mesma coisa, embora a última forma nunca deva aparecer fora da IOCCC .