Iterando con size_t 0 como condición límite

3 minutos de lectura

¿Cuál es la forma “correcta” de escribir un bucle decreciente con un valor de tamaño_t y una condición de contorno? Ejemplo de implementación incorrecta:

for (size_t elemNum = listSize-1; elemNum >= 0; --elemNum) { /* ... */ }

Cuando llegue a cero, volverá al valor máximo en lugar de actuar como una condición límite. Es necesario iterar el bucle a la inversa. Parece un problema que tendría una solución estándar de facto, pero no puedo encontrar cuál es.

El enfoque más sucinto es usar post-incremento:

for (size_t i = listSize; i--;) ...

  • umm, esto no se comportará de manera diferente a –i?

    – Jaime

    28 de agosto de 2011 a las 22:37

  • oh, ya veo, el incremento está en la condición. Culpa mía

    – Jaime

    28 de agosto de 2011 a las 22:39

  • Creo que funciona, pero en mi opinión, usar un bucle while como sugirió pmg es más fácil de entender que “usarlo incorrectamente” de esa manera.

    – Medo42

    28 de agosto de 2011 a las 22:40

  • @ Medo42: ¿Cómo es que el enfoque de ciclo while es menos un “mal uso”? Además, amplía el alcance de la variable de bucle más allá del bucle, lo que es mal karma.

    – Marcelo Cantos

    28 de agosto de 2011 a las 22:43

  • Me gusta más esta solución. Siempre que se entienda el operador “va a” mencionado en el otro comentario, puedo hacerlo aún más claro como: for (size_t i = listSize; i --> 0;) { /* ... */ }

    – Mark Langen

    29 de agosto de 2011 a las 19:52


elemNum = listsize;
while (elemNum--) {
    /* work with elemNum varying from `listsize - 1` down to `0` */
}

  • Algunos compiladores admiten el operador especial “va a”, while (elemNum --> 0) { /* ... */ } para este propósito.

    – KerrekSB

    28 de agosto de 2011 a las 22:50

  • @Kerrek: creo que te refieres a todos los compiladores que cumplen con el estándar 🙂

    – pmg

    28 de agosto de 2011 a las 22:53

  • @pmg, un pequeño detalle aquí: el elemNum no será 0 después de esto (habrá un ajuste justo después de la última iteración). Dado que el autor de la pregunta for el bucle ni siquiera hizo elemNum visible fuera del bucle, probablemente no importe, pero es (muy ligeramente) más limpio hacer la disminución como primera línea dentro del bucle.

    –Branko Dimitrijevic

    28 de agosto de 2011 a las 23:05

  • @Branko No creo que sea un pequeño detalle, sino un contraargumento real. Variables de índice local en for los bucles tienen razones, por lo que esta respuesta aquí no es apropiada.

    – Jens Gusted

    29 de agosto de 2011 a las 7:03

No conozco una forma estándar, pero esto debería funcionar:

for (size_t elemNum = listSize-1; elemNum < listSize; --elemNum) { /* ... */ }

  • Esa es una manera bastante ordenada de hacerlo.

    – Jaime

    28 de agosto de 2011 a las 22:34

  • no, es una forma bastante ofuscada. es tan feo que me gustaría votarlo negativo .. :/

    –Karoly Horvath

    28 de agosto de 2011 a las 22:37


  • Bueno, no lo veo nada complicado. Lo veo muy elegante e inteligente.

    – Diego Sevilla

    28 de agosto de 2011 a las 22:40

  • Creo que la solución de pmg es la mejor hasta ahora y la recomendaría sobre la mía.

    – Medo42

    28 de agosto de 2011 a las 22:42


  • Este enfoque es frágil. El tipo de la variable de bucle puede cambiar más tarde (p. ej., un programador de mantenimiento puede hacerlo para resolver las advertencias de comparación de tipos y puede olvidarse de inspeccionar correctamente el código), y entonces todas las apuestas están canceladas.

    – Marcelo Cantos

    28 de agosto de 2011 a las 22:46


Podrías usar dos variables en su lugar:

size_t count = 0;
for (size_t elemNum = listSize-1; count < listSize; ++count, --elemNum) { /* ... */ }

for (size_t counter = listSize; counter > 0; --counter) { 
     size_t index = counter-1;

    /* ... use `index` as an index ... */ 
}

Avatar de usuario de Branko Dimitrijevic
branco dimitrijevic

size_t elemNum = listSize;
while (elemNum > 0) {
    --elemNum;
    // Do your work here.
}

Avatar de usuario de James
Jaime

Podrías usar esto como la condición:

elemNum != (size_t)-1

O podría contar y hacer algunos cálculos (que el compilador probablemente optimizará de todos modos) para su índice:

for (size_t i = 1; i <= listSize; i++) {size_t elemNum = listSize-i; /* */}

¿Ha sido útil esta solución?