2010-08-13 11 views
89

Estaba leyendo algo de código y encontraron que la persona estaba usando arr[-2] para acceder al segundo elemento antes de la arr, así:¿Se permiten índices de matriz negativos en C?

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

Eso está permitido?

Sé que arr[x] es lo mismo que *(arr + x). Entonces, arr[-2] es *(arr - 2), lo que parece correcto. ¿Qué piensas?

Respuesta

146

Eso es correcto. De C99 §6.5.2.1/2:

La definición del operador subíndice [] es que E1 [E2] es idéntica a (* ((E1) + (E2))).

No hay magia. Es una equivalencia de 1-1. Como siempre, al desreferenciar un puntero (*), necesita estar seguro de que está apuntando a una dirección válida.

+1

Tenga en cuenta también que no es necesario desreferenciar el puntero para obtener UB. La mera computación de 'somearray-2' no está definida a menos que el resultado esté en el rango desde el comienzo de' somearray 'a 1 después de su finalización. – RBerteig

+20

En los libros más antiguos se hacía referencia a '[]' como una * sintaxis de azúcar * para la aritmética del puntero. * La forma favorita * de confundir a los principiantes es escribir '1 [arr]' - en lugar de 'arr [1]' - y verlos adivinar lo que eso significa. – Dummy00001

+4

¿Qué sucede en los sistemas de 64 bits (LP64) cuando tiene un índice int de 32 bits que es negativo? ¿Debería promoverse el índice a una int firmada de 64 bits antes del cálculo de la dirección? –

10

Me parece bien. Sin embargo, sería un caso raro que legítimamente lo necesitaras.

+6

No es * que * raro - es muy útil en, por ejemplo, procesamiento de imágenes con operadores de vecindario. –

59

Esto solo es válido si arr es un puntero que apunta al segundo elemento de una matriz o un elemento posterior. De lo contrario, no es válido, porque accedería a la memoria fuera de los límites de la matriz. Así, por ejemplo, este sería un error:

int arr[10]; 

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

Pero esto estaría bien:

int arr[10]; 
int* p = &arr[2]; 

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

Es, sin embargo, inusual para usar un subíndice negativo.

+0

No iría tan lejos como para decir que es inválido, solo potencialmente desordenado –

+10

@Matt: El código en el primer ejemplo arroja un comportamiento indefinido. –

+0

BSTR es un buen ejemplo en Windows. Cualquier asignador de depuración. No hay nada malo con eso –

7

Lo que probablemente era que arr apuntaba al centro de la matriz, por lo tanto, hacer arr[-2] apuntando a algo en la matriz original sin salir de los límites.

7

no estoy seguro de qué tan confiable es esto, pero acabo de leer la siguiente advertencia sobre los índices de matriz negativos en los sistemas de 64 bits (LP64 presumiblemente): http://www.devx.com/tips/Tip/41349

el autor parece estar diciendo que int de 32 bits los índices de matriz con direccionamiento de 64 bits pueden dar como resultado cálculos de direcciones incorrectas a menos que el índice de matriz se promueva explícitamente a 64 bits (por ejemplo, a través de un molde ptrdiff_t). De hecho, he visto un error de su naturaleza con la versión de PowerPC de gcc 4.1.0, pero no sé si es un error de compilación (es decir, debería funcionar de acuerdo con el estándar C99) o correcto (es decir, el índice necesita un molde para 64 bits para un comportamiento correcto)?

+3

Esto suena como un error del compilador. – tbleher

1

Sé que la pregunta es respondida, pero no pude resistirme a compartir esta explicación.

recuerdo Principios de diseño del compilador, Supongamos que a es una matriz y tamaño de int int es 2, & Dirección base para una es 1000.

Cómo 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)) 
i.e. 1000 + (5*2) = 1010 

Esta explicación es también la razón por la cual los índices negativos en arreglos funcionan en C.

es decir, si accedo a[-5] 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)) 
i.e. 1000 + (-5*2) = 990 

Se volverá me opongo en la ubicación 990. Por esta lógica podemos acceder a los índices negativos en Array en C.

1

Acerca de por qué alguien quiere usar índices negativos, los he usado en dos contextos:

  1. Tener una tabla de números combinatorios th at le dice peine [1] [- 1] = 0; siempre puede verificar los índices antes de acceder a la tabla, pero de esta forma el código se ve más limpio y se ejecuta más rápido.

  2. Colocando un centinela al comienzo de una tabla. Por ejemplo, desea utilizar algo así como

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

pero entonces también debe comprobar que i es positivo.
Solución: haga que a[-1] sea -DBLE_MAX, por lo que x&lt;a[-1] siempre será falso.

Cuestiones relacionadas