¿Por qué el hecho de no cambiar el incremento previo al post en la parte de iteración de un ciclo for hace la diferencia?

Por qué esto

int x = 2; for (int y =2; y>0;y--){ System.out.println(x + " "+ y + " "); x++; } 

imprime lo mismo que esto?

  int x = 2; for (int y =2; y>0;--y){ System.out.println(x + " "+ y + " "); x++; } 

Hasta ahora, como yo entiendo, un incremento posterior se usa primero “tal como es” y luego se incrementa. El preincremento se agrega primero y luego se usa. ¿Por qué esto no se aplica al cuerpo de un bucle for?

El ciclo es equivalente a:

 int x = 2; { int y = 2; while (y > 0) { System.out.println(x + " "+ y + " "); x++; y--; // or --y; } } 

Como puede ver al leer ese código, no importa si usa el operador de pre o decremento en la tercera sección del ciclo for.

Más generalmente, cualquier bucle for de la forma:

 for (ForInit ; Expression ; ForUpdate) forLoopBody(); 

es exactamente equivalente al ciclo while:

 { ForInit; while (Expression) { forLoopBody(); ForUpdate; } } 

El bucle for es más compacto y, por lo tanto, más fácil de analizar para una expresión tan común.

Para visualizar estas cosas, expanda el bucle for a un bucle while:

 for (int i = 0; i < 5; ++i) { do_stuff(i); } 

Se expande a:

 int i = 0; while (i < 5) { do_stuff(i); ++i; } 

No importa si realiza un incremento posterior o un incremento previo en el contador de bucles, porque el resultado de la expresión de incremento (el valor anterior o posterior al incremento) no se utiliza dentro de la misma instrucción.

No hay diferencia en términos de rendimiento, si esa es su preocupación. Solo se puede usar de forma incorrecta (y por lo tanto, sensible a los errores) cuando lo usa durante el incremento.

Considerar:

 for (int i = 0; i < 3;) System.out.print(++i + ".."); //prints 1..2..3 for (int i = 0; i < 3;) System.out.print(i++ + ".."); //prints 0..1..2 

o

 for (int i = 0; i++ < 3;) System.out.print(i + ".."); //prints 1..2..3 for (int i = 0; ++i < 3;) System.out.print(i + ".."); //prints 1..2 

Sin embargo, es interesante el detalle de que la expresión normal es usar i++ en la expresión incremental de la sentencia for y que el comstackdor de Java la comstackrá como si se utiliza ++i .

++ i e i ++ hacen una diferencia cuando se usan en combinación con el operador de asignación como int num = i ++ e int num = ++ i u otras expresiones. En el ciclo FOR anterior, solo hay una condición de incremento ya que no se usa en combinación con ninguna otra expresión, no hace ninguna diferencia. En este caso, solo significará i = i + 1.

Este ciclo es el mismo que este ciclo while:

 int i = 0; while(i < 5) { // LOOP i++; // Or ++i } 

Entonces sí, tiene que ser lo mismo.

Porque esa statement es solo por sí misma. El orden del incremento no importa allí.

Esos dos casos son equivalentes porque el valor de i se compara después de que se completa la statement de incremento. Sin embargo, si lo hiciste

 if (i++ < 3) 

versus

 if (++i < 3) 

tendrías que preocuparte por el orden de las cosas.

Y si lo hiciste

 i = ++i + i++; 

entonces estás loco.

Porque nada en sus ejemplos usa el valor devuelto por los incrementos previos o posteriores. Intente ajustar System.out.println() alrededor de ++x y x++ para ver la diferencia.

Desde el capítulo Especificación del lenguaje Java en bucles para :

BasicForStatement:

  for ( ForInit ; Expression ; ForUpdate ) Statement 

… si la parte ForUpdate está presente, las expresiones se evalúan en secuencia de izquierda a derecha; sus valores, si los hay, se descartan. … Si la parte ForUpdate no está presente, no se realiza ninguna acción.

(resaltar es mío).

El resultado es el mismo porque el elemento ‘incremento’ en ‘para (inicial; comparación; incremento)’ no usa el resultado de la instrucción, solo se basa en el efecto secundario de la statement, que en este caso es incrementando ‘i’, que es el mismo en ambos casos.

La comprobación se realiza antes de que se evalúe el argumento de incremento. La operación ‘incremento’ se realiza al final del ciclo, aunque se haya declarado al principio.

Prueba este ejemplo:

 int i = 6; System.out.println(i++); System.out.println(i); i = 10; System.out.println(++i); System.out.println(i); 

Debería poder averiguar qué hace a partir de esto.

Debido a que el valor de y se calcula en la instrucción for y el valor de x se calcula en su propia línea, pero en System.out.println solo se hace referencia a ellos.

Si disminuyes dentro de System.out.println , obtendrías un resultado diferente.

 System.out.println(y--); System.out.println(--y); 

Aquí hay muchas buenas respuestas, pero en caso de que esto ayude:

Piense en y– y – yy como expresiones con efectos secundarios, o una statement seguida de una expresión. y– es así (piense en estos ejemplos como pseudoensamblaje):

 decrement y return y 

yy hace esto:

 store y into t decrement y load t return t 

En el ejemplo de bucle, está descartando el valor devuelto en cualquier dirección y confiando únicamente en el efecto secundario (la comprobación de bucle ocurre DESPUÉS de que se ejecuta la instrucción de reducción, no recibe / comprueba el valor devuelto por la disminución).

Si el bucle for usa el resultado de la expresión i++ o ++i para algo, entonces sería cierto, pero ese no es el caso, está ahí simplemente porque es un efecto secundario.

Es por eso que también puede poner un método de void allí, no solo una expresión numérica.

El incremento se ejecuta como una statement independiente. Asi que

y–;

y

–y;

son equivalentes entre sí, y ambos son equivalentes a

y = y – 1;

Porque esto:

 int x = 2; for (int y =2; y>0; y--){ System.out.println(x + " "+ y + " "); x++; } 

El comstackdor lo traduce de manera efectiva a esto:

 int x = 2; int y = 2 while (y > 0){ System.out.println(x + " "+ y + " "); x++; y--; } 

Como puede ver, el uso de y-- o --y no --y ninguna diferencia. No obstante, marcaría la diferencia si escribieras tu ciclo así:

 int x = 2; for (int y = 3; --y > 0;){ System.out.println(x + " "+ y + " "); x++; } 

Esto arrojaría el mismo resultado que sus dos variantes del ciclo, pero cambiar de --y a y-- aquí rompería su progtwig.

Es una cuestión de gusto. Ellos hacen las mismas cosas.

Si observas el código de las clases de Java, verás for-loop con incrementos posteriores.

en tu caso, es lo mismo, no hay diferencia en absoluto.

Tienes razón. La diferencia se puede ver en este caso:

 for(int i = 0; i < 5; ) { System.out.println("i is : " + ++i); } 

Sí lo hace secuencialmente. Inicialización, luego condición de evaluación y si es verdadero, luego ejecutar el cuerpo y luego incrementarlo.

La diferencia de prefijo y postfijo solo se podrá notar cuando realice una operación de Asignación con Incremento / Decremento.

No hay diferencias porque cada parte de los “argumentos” son declaraciones separadas.

Y una cosa interesante es que el comstackdor puede decidir reemplazar las post-elevaciones simples por pre-incrementos y esto no cambiará nada al código.

NO se comportan igual. La construcción con i ++ es un poco más lenta que la que tiene ++ ++ porque la primera implica devolver tanto los valores antiguos como los nuevos de i . Por otro lado, este último solo devuelve el valor anterior de i .

Entonces, probablemente el comstackdor haga un poco de magia y cambie cualquier i ++ aislado en a ++ i por razones de rendimiento, pero en términos de algoritmo en bruto no son estrictamente lo mismo.

Hay muchas publicaciones similares en Stackoverflow:

  • Diferencia entre i ++ y ++ i en un bucle?
  • ¿Hay alguna diferencia de rendimiento entre ++ i e i ++ en C #?
  • ¿Hay una diferencia de rendimiento entre i ++ y ++ i en C?

Sin embargo, parece que su pregunta es más genérica porque no es específica de ningún lenguaje o comstackdor. La mayoría de las preguntas anteriores se refieren a un lenguaje / comstackdor específico.

Aquí hay un resumen:

  • si estamos hablando de C / C ++ / Java (probablemente también C #) y un comstackdor moderno:
    • si i es un número entero ( const int , int , etc.):
      • entonces el comstackdor básicamente reemplazará i++ con ++i , porque son semánticamente idénticos y por lo tanto no cambia la salida. esto puede verificarse verificando el código / código de bytes generado (para Java, uso el visor de códigos de bytes jclasslib ).
    • más:
  • más:
    • todas las apuestas están apagadas, porque el comstackdor no puede garantizar que sean semánticamente idénticas, por lo que no intenta optimizar.

Por lo tanto, si tiene una clase en C ++ que anula los operadores postfix y prefijo (como std::iterator ), esta optimización rara vez se realiza.

En resumen:

  • Significa lo que dices, y di lo que quieres decir. Para la parte de incremento de los bucles for , casi siempre quiere la versión de prefijo (es decir, ++i ).
  • La conmutación del comstackdor entre ++i e i++ no siempre se puede hacer, pero intentará hacerlo por usted si puede.

en un bucle, primera inicialización, luego comprobación de condición, luego ejecución, después de ese incremento / decremento. entonces el incremento / decremento pre / post no afecta el código del progtwig.

Acerca de i ++ (post-incremento) vs. ++ i (pre-incremento) @me: “En ambos casos, la expresión se evalúa y el resultado se usa para verificar la condición. En el caso de incremento previo, el incremento expresión incrementa la variable y devuelve el valor resultante. Para el incremento posterior, la expresión de incremento también incrementa la variable, pero devuelve el valor anterior. Como resultado, el preincremento se compara con el valor incrementado, mientras que el incremento posterior se compara con el valor original; en ambos casos, la variable se ha incrementado cuando se verifica la condición “. – tdammers

Existe una gran confusión entre el operador de post-producción y el de pre-incremento, esto se puede entender fácilmente a partir de este extracto de “Algorithms, 4th Edition” de Robert Sedgewick y Kevin Wayne.

Operadores de incremento / decremento: i ++ es lo mismo que i = i + 1 y tiene el valor i en una expresión. De manera similar, i– es lo mismo que i = i – 1. El código ++ iy – i son iguales excepto que el valor de expresión se toma después del incremento / decremento, no antes.

por ejemplo

 x = 0; post increment: x++; step 1: assign the old value (0) value of the x back to x.So, here is x = 0. step 2: after assigning the old value of the x, increase the value of x by 1. So, x = 1 now; when try to print somthing like: System.out.print(x++); the result is x : 0. Because only step one is executed which is assigning old value of the x back and then print it. But when, we do operation like this: i++; System.out.print(i); the result is x: 1. which is because of executing Step one at first statement and then step two at the second statement before printing the value. pre increment: ++x; step 1: increase the value of x by 1. So, x = 1 now; step 2: assign the increased value back to x. when try to print something like: System.out.print(++1) the result is x : 1. Because the value of the x is raised by 1 and then printed. So, both steps are performed before print x value. Similarly, executing ++i; system.out.print(i); Both steps are executed at statement one. At second statement, just the value of "i" is printed.