2012-01-28 22 views
8

Ho fatto qualche ricerca su Stackoverflow sul reverse per loop in C++ che usano un intero senza segno invece di uno firmato. Ma ancora non capisco perché c'è un problema (vedi Unsigned int reverse iteration with for loops). Perché il codice seguente produrrà un errore di segmentazione?Numeri interi senza segno in C++ per loop

#include <vector> 
#include <iostream> 
using namespace std; 

int main(void) 
{ 
    vector<double> x(10); 

    for (unsigned int i = 9; i >= 0; i--) 
    { 
     cout << "i= " << i << endl; 
     x[i] = 1.0; 
    } 

    cout << "x0= " << x[0] << endl; 

    return 0; 
} 

Capisco che il problema è quando l'indice i sarà pari a zero, perché c'è qualcosa di simile a un overflow. Ma penso che un intero senza segno sia autorizzato a prendere il valore zero, non è vero? Ora se lo sostituisco con un numero intero con segno, non c'è assolutamente alcun problema.

Qualcuno può spiegarmi il meccanismo dietro quel ciclo inverso con un numero intero senza segno?

Grazie mille!

+3

'i> = 0' è sempre vero per unsigned' i', quindi il ciclo non termina mai. – TonyK

+0

Leggi gli avvertimenti del compilatore, sono utili. In questo caso, probabilmente il compilatore dovrebbe averti avvertito del fatto che la condizione nel tuo loop è sempre vera. – dragonroot

+0

@dragonroot: Purtroppo no. Io uso il flag -Wall di g ++. Conoscete un flag del compilatore che rileverà questo tipo di problema? Grazie. – Benjamin

risposta

24

Il problema qui è che un numero intero senza segno non è mai negativo.

Pertanto, il ciclo-test:

i >= 0 

sarà sempre vero. Così ottieni un ciclo infinito.

Quando scende sotto lo zero, si avvolge attorno al valore massimo unsigned.
Pertanto, si accederà anche allo x[i] fuori limite.

Questo non è un problema per gli interi con segno perché sarà semplicemente negativo e quindi fallirà i >= 0.

Così, se si desidera utilizzare numeri interi senza segno, si può provare una delle seguenti possibilità:

for (unsigned int i = 9; i-- != 0;) 

e

for (unsigned int i = 9; i != -1; i--) 

Questi due sono stati suggeriti da GManNickG e AndreyT dai commenti.


Ed ecco i miei originali 3 versioni:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--) 

o

for (unsigned int i = 9; i != ~(unsigned)0; i--) 

o

for (unsigned int i = 9; i != UINT_MAX; i--) 
+0

Oppure "i" è * un altro * rispetto all'indice, in modo che "0" sia una condizione di terminazione appropriata. Per quanto complicato come il resto però. –

+0

Il comportamento non definito di overflow e underflow non è intero? – josefx

+2

@josefx Solo l'over/underflow con segno intero con segno è un comportamento non definito. – Mysticial

4

Qualunque sia il valore di unsigned int i è sempre vero che i >= 0 così y il nostro ciclo for non finisce mai.

In altre parole, se a un certo punto i è 0 e farlo diminuire, rimane ancora non negativo, perché contiene poi un numero enorme, probabilmente 4294967295 (cioè 2 -1).

6

Il problema è che il loop consente di essere basso come zero e si aspetta solo di uscire dal ciclo se i è minore di 0. Poiché i non è firmato, non può mai essere inferiore a 0. Passa a 2^32-1.Questo è maggiore della dimensione del tuo vettore e quindi risulta in un segfault.

3

Il problema è qui:

for (unsigned int i = 9; i >= 0; i--) 

si inizia con un valore di 9 per un unsigned int e la tua definizione di uscita è i> = 0 e questo sarà sempre vero. (int non firmato non sarà mai negativo !!!). A causa di ciò, il ciclo ricomincia (ciclo infinito, perché i = 0, quindi -1 va al massimo uint).

Problemi correlati