Os índices de matriz negativa são permitidos em C?

Eu estava lendo algum código e descobri que a pessoa estava usando arr[-2] para acessar o segundo elemento antes do arr , assim:

 |a|b|c|d|e|f|g| ^------------ arr[0] ^---------- arr[1] ^---------------- arr[-2] 

Isso é permitido?

Eu sei que arr[x] é o mesmo que *(arr + x) . Então arr[-2] é *(arr - 2) , o que parece OK. O que você acha?

   

Está correto. De C99 §6.5.2.1 / 2:

A definição do operador de subscrição [] é que E1 [E2] é idêntico a (* ((E1) + (E2))).

Não há mágica. É uma equivalência 1-1. Como sempre ao desreferenciar um ponteiro (*), você precisa ter certeza de que está apontando para um endereço válido.

Isso só é válido se arr for um ponteiro que aponta para o segundo elemento em uma matriz ou um elemento posterior. Caso contrário, não é válido, porque você estaria acessando a memory fora dos limites da matriz. Então, por exemplo, isso seria errado:

 int arr[10]; int x = arr[-2]; // invalid; out of range 

Mas isso ficaria bem:

 int arr[10]; int* p = &arr[2]; int x = p[-2]; // valid: accesses arr[0] 

No entanto, é incomum usar um índice negativo.

Soa bem para mim. Seria um caso raro que você precisaria legitimamente, no entanto.

O que provavelmente era que arr estava apontando para o meio da matriz, fazendo arr[-2] apontar para algo na matriz original sem sair dos limites.

Não tenho certeza de como isso é confiável, mas acabei de ler a seguinte advertência sobre os índices de matriz negativa em sistemas de 64 bits (presumivelmente LP64): http://www.devx.com/tips/Tip/41349

O autor parece estar dizendo que índices de matriz int de 32 bits com endereçamento de 64 bits podem resultar em cálculos de endereço incorreto, a menos que o índice de matriz seja promovido explicitamente a 64 bits (por exemplo, por meio de um ptrdiff_t convertido). Eu realmente vi um bug de sua natureza com a versão PowerPC do gcc 4.1.0, mas eu não sei se é um bug do compilador (ou seja, deve funcionar de acordo com o padrão C99) ou o comportamento correto (ou seja, índice precisa de um casting para 64 bits para o comportamento correto)?

Eu sei que a pergunta está respondida, mas não pude resistir em compartilhar essa explicação.

Lembro-me do design Princípios do Compilador, Vamos assumir que um é um array int e o tamanho de int é 2, e o endereço Base para a é 1000.

Como a[5] funcionará ->

 Base Address of your Array a + (index of array *size of(data type for array a)) Base Address of your Array a + (5*size of(data type for array a)) ie 1000 + (5*2) = 1010 

Essa explicação é também a razão pela qual índices negativos em matrizes funcionam em C.

ou seja, se eu acessar a[-5] ele me dará

 Base Address of your Array a + (index of array *size of(data type for array a)) Base Address of your Array a + (-5 * size of(data type for array a)) ie 1000 + (-5*2) = 990 

Ele me retornará o object no local 990. Por essa lógica, podemos acessar índices negativos em Array em C.

Por que alguém iria querer usar índices negativos? Eu os usei em dois contextos:

  1. Ter uma tabela de números combinatórios que diz para você pentear [1] [- 1] = 0; Você sempre pode verificar os índices antes de acessar a tabela, mas desta forma o código parece mais limpo e executa mais rápido.

  2. Colocar um centinel no início de uma mesa. Por exemplo, você quer usar algo como

      while (x < a[i]) i--; 

mas então você também deve verificar se i é positivo.
Solução: faça com que a[-1] seja -DBLE_MAX , de modo que x<a[-1] seja sempre falso.