Pregunta ¿Cuál es la mejor manera de hacer un ciclo inverso 'para' con un índice sin firmar?


Mi primer intento de invertir para el lazo eso hace algo n veces era algo así como:

for ( unsigned int i = n-1; i >= 0; i-- ) {
    ...     
}

Esta falla porque en aritmética sin signo  i se garantiza que siempre será mayor o igual que cero, por lo tanto, la condición de bucle siempre será verdadera. Afortunadamente, el compilador gcc me advirtió sobre una "comparación inútil" antes de que tuviera que preguntarme por qué el ciclo se estaba ejecutando infinitamente.


Estoy buscando una forma elegante de resolver este problema, teniendo en cuenta que:

  1. Debería ser un ciclo hacia atrás para.
  2. El índice de ciclo debe estar sin signo.
  3. n es constante sin signo.
  4. No debe basarse en la aritmética de anillo "oscura" de enteros sin signo.

¿Algunas ideas? Gracias :)


50
2018-03-20 11:26


origen


Respuestas:


Qué tal si:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}

83
2018-03-20 11:35



for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

o

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 

11
2018-03-20 11:30



for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

Tenga en cuenta que si usa tanto C ++ como C, usar! = Es un buen hábito al que recurrir cuando utiliza iteradores, donde <= etc. puede no estar disponible.


11
2018-03-20 11:29



for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}

8
2018-03-20 11:30



Tiendo a usar

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

es casi lo mismo que la respuesta de skizz, (se pierde un decremento innecesario final, pero el compilador debe optimizar eso), y en realidad pasará la revisión del código. Cada estándar de codificación con el que he tenido que trabajar ha tenido una no mutación en la regla condicional.


8
2018-03-20 11:44



¿Por qué no simplemente?

unsigned int i = n;
while(i--)
{ 
    // use i
}

Esto cumple con todos los requisitos enumerados en el cuerpo de la pregunta. No utiliza nada que pueda fallar en la revisión del código o que viole un estándar de codificación. La única objeción que pude ver es si el OP realmente insistió en una for loop y no una forma directa de generar i = (n-1) .. 0.


8
2018-05-11 07:30



Quizás de esta manera? En mi humilde opinión, es claro y legible. Puede omitir el if (n> = 1) si se conoce implícitamente de alguna manera.

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

Otra version:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

El primer código sin la declaración if se vería así:

unsigned int i = n-1;
do {

} while( i-- != 0 );

5
2018-03-20 11:52



O podría confiar en el comportamiento de envoltura de unsigned int si necesita indexar de n-1 a 0

for(unsigned int i = n-1; i < n; i--) {
    ...
}

4
2018-03-20 13:05



for ( unsigned int i = n; i > 0; i-- ) {
    unsigned int x = i - 1;
    // do whatever you want with x    
}

Ciertamente no es elegante, pero funciona.


3
2018-03-20 11:32



for (unsigned int i = n-1; i<(unsigned int)-1; i--)

OK, es "aritmética de anillo oscuro".


3
2018-03-20 12:34



La única razón por la que menciono esta opción es porque no la vi en la lista.

for ( unsigned int i = n-1; i < n; i-- ) {
... 
}

Totalmente en contra de la intuición, pero funciona. la razón por la que funciona es porque al restar 1 de 0 se obtiene el mayor número que se puede representar con un entero sin signo.

En general, no creo que sea una buena idea trabajar con enteros sin signo y arthmetic, especialmente al restar.


3
2018-03-20 13:08