Подтвердить что ты не робот

Почему не меняется префикс до приращения записи в итерационной части цикла for?

Почему это

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

печатает то же самое, что и это?

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

Насколько я понимаю, пост-инкремент сначала используется "как есть", затем увеличивается. Сначала добавляется предварительный инкремент, а затем используется. Почему это не относится к телу цикла for?

4b9b3361

Ответ 1

Цикл эквивалентен:

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

Как видно из чтения этого кода, не имеет значения, используете ли вы оператор post или pre декремента в третьем разделе цикла for.

В общем случае любой для цикла вида:

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

точно эквивалентен циклу while:

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

Цикл for более компактен и, таким образом, легче анализировать такую ​​общую идиому.

Ответ 2

Чтобы визуализировать эти вещи, разверните цикл for в цикл while:

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

Расширяется до:

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

Если вы выполняете пост-инкремент или предварительный инкремент на счетчике циклов, это не имеет значения, потому что результат выражения инкремента (либо значение до, либо после инкремента) не используется в пределах одного и того же оператора.

Ответ 3

Нет никакой разницы в показателях производительности, если это вас беспокоит. Он может использоваться только неправильно (и, следовательно, чувствителен к ошибкам), когда вы используете его в течение приращения.

Рассмотрим:

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

или

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

Интересной деталью является то, что нормальная идиома должна использовать i++ в выражении приращения оператора for и что компилятор Java будет скомпилировать его, как если бы использовался ++i.

Ответ 4

++ я и я ++ имеют значение при использовании в сочетании с оператором присваивания, таким как int num = я ++ и int num = ++ я или другие выражения. В вышеприведенном цикле FOR существует только дополнительное условие, поскольку оно не используется в сочетании с каким-либо другим выражением, оно не имеет никакого значения. В этом случае это будет означать только я = я + 1.

Ответ 5

Этот цикл такой же, как этот цикл while:

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

Итак, да, это должно быть одно и то же.

Ответ 6

Потому что это утверждение просто на его собственном. Порядок приращения там не имеет значения.

Ответ 7

Эти два случая эквивалентны, потому что значение я сравнивается после выполнения инструкции increment. Однако, если вы сделали

if (i++ < 3) 

против

if (++i < 3)

вам придется беспокоиться о порядке вещей.

И если вы сделали

i = ++i + i++;

тогда вы просто орехи.

Ответ 8

Потому что ничто в ваших примерах не использует значение, возвращенное из пре-или пост-приращений. Попробуйте обернуть System.out.println() вокруг ++x и x++, чтобы увидеть разницу.

Ответ 9

В главе глава Java Language Specification для циклов петель:

BasicForStatement:

    for ( ForInit ; Expression ; ForUpdate ) Statement

... если часть ForUpdate присутствует, выражения вычисляются в последовательность слева направо; их значения, если они есть, отбрасываются.... Если часть ForUpdate отсутствует, никаких действий не предпринимается.

(выделение - мое).

Ответ 10

Результат тот же, поскольку элемент "increment" в "for (initial; compare; increment)" не использует результат инструкции, он просто полагается на побочный эффект выражения, который в этот случай увеличивает значение "i", что в обоих случаях одинаково.

Ответ 11

Проверка выполняется до вычисления аргумента increment. Операция "increment" выполняется в конце цикла, даже если она была объявлена ​​в начале.

Ответ 12

Попробуйте этот пример:

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

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

Вы должны уметь выработать то, что он делает.

Ответ 13

Поскольку значение y вычисляется в выражении for, а значение x вычисляется в его собственной строке, но в System.out.println они ссылаются только на.

Если вы уменьшаетесь внутри System.out.println, вы получите другой результат.

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

Ответ 14

Здесь есть много хороших ответов, но в случае, если это поможет:

Подумайте о y-- и -y как выражениях с побочными эффектами или о выражении, сопровождаемом выражением. y-- так (подумайте об этих примерах как псевдо-сборке):

decrement y
return y

и --y делает следующее:

store y into t
decrement y
load t
return t

В примере вашего цикла вы выбрасываете возвращаемое значение в любом случае и полагаетесь только на побочный эффект (проверка цикла происходит ПОСЛЕ выполнения инструкции декремента, она не принимает/не проверяет значение, возвращаемое декрементом).

Ответ 15

Если цикл for использовал результат выражения i++ или ++i для чего-то, тогда это было бы правдой, но это не так, это просто потому, что его побочный эффект.

Вот почему вы также можете поместить здесь метод void, а не только числовое выражение.

Ответ 16

Приращение выполняется как независимый оператор. Так

у -;

и

- у;

эквивалентны друг другу, и оба эквивалентны

y = y - 1;

Ответ 17

Потому что это:

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

Эффективно переводится компилятором на это:

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

Как вы видите, использование y-- или --y не приводит к какой-либо разнице. Было бы полезно, если бы вы написали свой цикл следующим образом:

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

Это приведет к тому же результату, что и ваши два варианта цикла, но переход от --y в y-- приведет к поломке вашей программы.

Ответ 18

Это вопрос вкуса. Они делают то же самое.

Если вы посмотрите на код классов java, вы увидите, что для циклов с последующим приращением вы увидите.

Ответ 19

в вашем случае, это то же самое, никакой разницы вообще.

Ответ 20

Вы правы. Разницу можно увидеть в этом случае:

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

Ответ 21

Да, он делает это последовательно. Intialisation, затем условие оценки, и если true, то выполняется тело, а затем увеличивается.

Префикс и постфиксная разница будут заметны только тогда, когда вы выполняете операцию присваивания с помощью Приращения/Уменьшения.

Ответ 22

Нет различий, потому что каждая часть аргументов "arguments" является разделяемыми операторами.

И интересно то, что компилятор может решить заменить простые пост-инкременции на предварительные инкрементации, и это не изменит вещь на код.

Ответ 23

Они НЕ ведут себя одинаково. Конструкция с я ++ немного медленнее, чем с ++ i, потому что первая включает в себя возврат как старых, так и новых значений i. С другой стороны, последнее возвращает только старое значение i.

Затем, вероятно, компилятор делает небольшую магию и меняет любой изолированный я ++ на ++ i по соображениям производительности, но с точки зрения необработанного алгоритма они не строго то же самое.

Ответ 24

Там много похожих сообщений в Stackoverflow:

Однако, похоже, ваш вопрос более общий, поскольку он не является специфическим для какого-либо языка или компилятора. Большинство из вышеперечисленных вопросов касаются конкретного языка/компилятора.

Вот краткое изложение:

  • если мы говорим о C/С++/Java (возможно, С# тоже) и современном компиляторе:
    • если i - целое число (const int, int и т.д.):
      • тогда компилятор в основном заменит i++ на ++i, потому что они семантически идентичны и поэтому не изменят вывод. это можно проверить, проверив сгенерированный код/​​байт-код (для Java я использую jclasslib просмотрщик байтов).
    • еще:
  • еще:
    • все ставки отключены, поскольку компилятор не может гарантировать, что они семантически идентичны, поэтому он не пытается оптимизировать.

Итак, если у вас есть класс на С++, который переопределяет операторы постфикса и префикса (например, std::iterator), эта оптимизация выполняется редко, если вообще когда-либо делается.

Вкратце:

  • Знайте, что вы говорите, и говорите, что вы имеете в виду. Для инкрементной части циклов for вы почти всегда хотите версию префикса (т.е. ++i).
  • Компилятор switchcheroo между ++i и i++ не всегда может быть выполнен, но он попытается сделать это для вас, если это возможно.

Ответ 25

в цикле, первая инициализация, затем проверка условий, затем выполнение, после этого приращения/уменьшения. поэтому pre/post increment/decment не влияет на программный код.

Ответ 26

О я ++ (post-incrementation) vs. ++ я (pre-incrementation) @me: "В обоих случаях выражение получает оценку, и результат используется для проверки на условие. В случае pre-increment, выражение приращения увеличивает значение переменной и возвращает результирующее значение.Для последующего приращения выражение increment также увеличивает эту переменную, но возвращает предыдущее значение. В результате pre-increment сравнивается с приращенным значением, тогда как приращение сравнивается с исходным значением, и в обоих случаях переменная была увеличена, когда условие проверено." - tdammers