Perché è possibile accedere a un array senza limiti con indici negativi molto più che con indici positivi?

-2

Ho scritto due piccoli programmi in cui dichiaro un array molto piccolo.

Quindi provo ad accedere ai valori fuori dai limiti.

La cosa interessante che ho notato è che quando provo a decrementare l'indice posso decrementarlo molto molto più lontano. Se provo ad incrementarlo, il programma si blocca molto più velocemente.

Questo sono i miei due codici e i risultati:

 #include<stdio.h>
 int main()
 {
     int i=0;                                                                
     int a[2];

     while(1)
     {
         a[-10000]=8;
         printf("i is: %d and the value a[i] is: %d\n",i,a[i]);
         i--;

      }

      return 0;
 }

Le righe finali del risultato sono:

i è: -3143957 il valore di a [i] è: 0 i è: -3143958 il valore di a [i] è: 0 i è: -3143959 il valore di a [i] è: 0 i è: -3143960 il valore di a [i] è: 0 i è: -3143961 il valore di a [i] è: 0 i è: -3143962 il valore di a [i] è: 0 i è: -3143963 il valore di a [i] è: 0 i è: -3143964 il valore di a [i] è: 0 Errore di segmentazione

Tuttavia quando provo ad incrementare l'indice i

 #include<stdio.h>
 int main()
 {
     int i=0;                                                                
     int a[2];

     while(1)
     {
         a[-10000]=8;
         printf("i is: %d and the value a[i] is: %d\n",i,a[i]);
         i++;

      }

      return 0;
 }

Ottengo il seguente risultato: i è: 2306 e il valore a [i] è: 1869098813 i è: 2307 e il valore a [i] è: 1764713837 i è: 2308 e il valore a [i] è: 1634624869 i è: 2309 e il valore a [i] è: 795175011 i è: 2310 e il valore a [i] è: 1802724676 i è: 2311 e il valore a [i] è: 7368564 i è: 2312 e il valore a [i] è: 778121006 i è: 2313 e il valore a [i] è: 7632239 i è: 2314 e il valore a [i] è: 0 i è: 2315 e il valore a [i] è: 0

La differenza tra quanto posso salire e quanto posso andare giù è ENORME. Perché è così.

Alcune cose da menzionare: SO che questo è un comportamento indefinito. La mia domanda è strettamente su PERCHÉ posso andare molto più in alto rispetto a GIU quando si esce da una serie di array.

    
posta yoyo_fun 14.09.2017 - 10:16
fonte

1 risposta

2

È per lo più una coincidenza che puoi leggere più garbage decrementando che incrementando.

È probabile che il compilatore abbia inserito l'indirizzo di a[0] nello stack. Il compilatore avrà anche riservato un po 'di memoria per lo stack in generale e probabilmente metterà una pagina di guardia dopo quella memoria per catturare gli overflow dello stack.

Quello che sospetto stia succedendo quando decrementi è che stai camminando lungo la memoria dello stack riservato fino a quando non colpisci la pagina di guardia e seggi l'errore.

Ora, il compilatore avrà riservato memoria globale per varie cose nel runtime sopra lo stack. Quello che sospetto stia accadendo quando si incrementa è che sta camminando quella memoria fino a quando non colpisce un altro errore di pagina sulla memoria che non può leggere. È probabile che abbia riservato meno memoria globale rispetto alla memoria di stack, quindi può aumentare di meno di quanto possa diminuire.

Puoi sperimentare con questo. Ad esempio, inserendo una grande matrice sulla pila prima della dichiarazione int a[2] , dovresti essere in grado di camminare su quella memoria aggiuntiva prima di eseguire il comando barfs. Se ciò non funziona (potrebbe non essere il compilatore in grado di riordinare le variabili nello stack all'interno di una funzione) quindi disporre della matrice grande in main e inserire il ciclo di walk walk in una funzione chiamata da main fai il trucco.

Nota, tuttavia, questo è tutto in gran parte supposizione senza conoscere i dettagli sulla macchina, sul sistema operativo e sul compilatore. Ad esempio, suppongo che lo stack cresca verso il basso, il che non è universalmente vero.

BTW non è sicuro del perché tu abbia l'istruzione a[-10000]=8; ma probabilmente non sta facendo quello che pensi che stia facendo. In particolare, il compilatore sarà, quasi sicuramente, in grado di stabilire staticamente che questo è UB e, essendo UB, potrebbe scegliere di fare qualsiasi cosa con esso; la rimozione completa è la più probabile.

    
risposta data 14.09.2017 - 11:38
fonte

Leggi altre domande sui tag