2010-08-13 22 views
89

Stavo leggendo un codice e ha scoperto che la persona stava usando arr[-2] per accedere al secondo elemento prima del arr, in questo modo:Gli indici di array negativi sono consentiti in C?

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

È che domestici?

So che lo arr[x] è lo stesso di *(arr + x). Quindi arr[-2] è *(arr - 2), che sembra OK. Cosa ne pensi?

risposta

146

Ciò è corretto. Da C99 §6.5.2.1/2:

La definizione del pedice operatore [] è che E1 [E2] è identica a (* ((E1) + (E2))).

Non c'è magia. È un'equivalenza di 1-1. Come sempre quando si dereferenzia un puntatore (*), è necessario assicurarsi che stia puntando a un indirizzo valido.

+1

Nota anche che non devi dereferenziare il puntatore per ottenere UB. Il semplice calcolo di 'somearray-2' non è definito a meno che il risultato non sia compreso nell'intervallo dall'inizio di' somearray' a 1 dopo la sua fine. – RBerteig

+20

Nei libri più vecchi il '[]' è stato referenziato come * sintassi sugar * per l'aritmetica del puntatore. * Il modo preferito per confondere i principianti è quello di scrivere '1 [arr]' - invece di 'arr [1]' - e vederli indovinare cosa vorrebbe dire. – Dummy00001

+4

Cosa succede sui sistemi a 64 bit (LP64) quando si ha un indice int a 32 bit che è negativo? L'indice dovrebbe essere promosso a un int con firma a 64 bit prima del calcolo dell'indirizzo? –

10

Mi sembra soddisfacente. Sarebbe un caso raro che tu lo possa legittimamente aver bisogno comunque.

+6

Non è * che * raro - è molto utile ad es. elaborazione delle immagini con gli operatori del quartiere. –

59

Questo è valido solo se arr è un puntatore che punta al secondo elemento di un array o di un elemento successivo. Altrimenti, non è valido, perché si accede alla memoria fuori dai limiti dell'array. Così, per esempio, questo sarebbe sbagliato:

int arr[10]; 

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

Ma questo sarebbe bene:

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

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

E ', tuttavia, inusuale per usare un pedice negativo.

+0

Non direi che non è valido, solo potenzialmente disordinato –

+10

@Matt: il codice nel primo esempio produce un comportamento indefinito. –

+0

BSTR è un buon esempio in Windows. Qualsiasi allocatore di debug. Niente di male in questo. –

7

Probabilmente era arr che puntava verso il centro dell'array, quindi facendo sì che arr[-2] puntasse a qualcosa nell'array originale senza uscire dai limiti.

7

io non sono sicuro di come affidabile questo è, ma ho appena letto il seguente avvertimento circa gli indici degli array negativi sui sistemi a 64 bit (LP64 presumibilmente): http://www.devx.com/tips/Tip/41349

l'autore sembra voler dire che a 32 bit int indici di array con indirizzamento a 64 bit possono causare calcoli di indirizzi errati a meno che l'indice di matrice non venga promosso esplicitamente a 64 bit (ad esempio tramite un cast di ptrdiff_t). Ho visto un bug della sua natura con la versione PowerPC di gcc 4.1.0, ma non so se si tratta di un bug del compilatore (cioè dovrebbe funzionare secondo lo standard C99) o di un comportamento corretto (cioè l'indice richiede un cast per 64 bit per un comportamento corretto)?

+3

Sembra un bug del compilatore. – tbleher

1

So che la domanda è stata risolta, ma non ho potuto resistere alla condivisione di questa spiegazione.

ricordo Principi di progettazione del compilatore, Ipotizziamo un è un array int e la dimensione del int è 2, & indirizzo di base per una è 1000.

Come funzionerà a[5] ->

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 

Questa spiegazione è anche la ragione per cui gli indici negativi negli array funzionano in C.

cioè se accedo a[-5] mi 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 

Si ritornerà mi oppongo a posizione 990. Con questa logica possiamo accedere indici negativi in ​​Array in C.

1

proposito perché avrebbe qualcuno vuole usare gli indici negativi, li ho usati in due contesti:

  1. Avere una tabella di numeri combinatori th a ti dice pettine [1] [- 1] = 0; puoi sempre controllare gli indici prima di accedere alla tabella, ma in questo modo il codice sembra più pulito e viene eseguito più velocemente.

  2. Mettere un centinel all'inizio di un tavolo. Per esempio, si desidera utilizzare qualcosa come

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

ma allora si dovrebbe anche controllare che i è positivo.
Soluzione: fare in modo che a[-1] sia -DBLE_MAX, in modo che x&lt;a[-1] sia sempre falso.

Problemi correlati