Разница между я ++ и ++ я в цикле?

Есть ли разница в ++i и i++ в цикле for? Это просто синтаксис?

Ответы

Ответ 1

a ++ известен как постфикс.

добавить 1 в a, возвращает старое значение.

++ a известен как префикс.

добавить 1 в a, возвращает новое значение.

С#:

string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
    Console.WriteLine(++i);
}
Console.WriteLine("");

i = 0;
foreach (string item in items)
{
    Console.WriteLine(i++);
}

Вывод:

1
2
3
4

0
1
2
3

foreach и while зависят от типа используемого вами типа инкремента. Поскольку для таких циклов, как показано ниже, не имеет значения, поскольку вы не используете возвращаемое значение i:

for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }

0 1 2 3 4
0 1 2 3 4

Если используется значение с оценкой, тип приращения становится значительным:

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

Ответ 2

Pre-increment ++i увеличивает значение я и оценивает новое добавочное значение.

int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );

Post-increment i++ увеличивает значение я и оценивает исходное значение без приращения.

int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );

В C++ предварительный приращение обычно предпочтительнее, если вы можете использовать его.

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

Таким образом, по крайней мере, в C++ может быть разница в производительности, которая поможет вам выбрать, какой из них использовать.

В основном это проблема только в том случае, когда переменная, которая увеличивается, является пользовательским типом с переопределенным оператором ++. Для примитивных типов (int и т.д.) Нет разницы в производительности. Но стоит упомянуть оператора pre-increment в качестве ориентира, если оператор post-increment определенно не требуется.

Там еще несколько обсуждений:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm

В C++, если вы используете STL, вы можете использовать для циклов с итераторами. Они в основном имеют переопределенные операторы ++, поэтому прилипание к предварительному приращению - хорошая идея. Компиляторы становятся все умнее все время, но более новые могут быть способны выполнять оптимизацию, что означает отсутствие разницы в производительности - особенно, если увеличиваемый тип определяется встроенным в заголовочный файл (как часто реализуются STL-реализации), чтобы компилятор мог видеть, как этот метод реализуется и может затем знать, какие оптимизации безопасны для выполнения. Тем не менее, возможно, все еще стоит придерживаться предварительного инкремента, потому что циклы выполняются много раз, и это означает, что вскоре может быть усилено небольшое снижение производительности.


В других языках, таких как С#, где оператор ++ не может быть перегружен, нет разницы в производительности. Операторы pre и post increment, используемые в цикле для продвижения переменной цикла, эквивалентны.

Коррекция: допускается перегрузка ++ в С#. Кажется, что, по сравнению с C++, в С# вы не можете перегружать версии pre и post независимо. Итак, я бы предположил, что если результат вызова ++ в С# не присваивается переменной или не используется как часть сложного выражения, тогда компилятор сократит до и после версий ++ до кода, который будет выполняться эквивалентно.

Ответ 3

В С# нет разницы при использовании в цикле for.

for (int i = 0; i < 10; i++) { Console.WriteLine(i); }

выводит то же самое, что и

for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }

Как указывали другие, при использовании в целом я ++ и ++ у меня есть тонкая, но существенная разница:

int i = 0;
Console.WriteLine(i++);   // Prints 0
int j = 0;
Console.WriteLine(++j);   // Prints 1

i ++ читает значение i, затем увеличивает его.

++ я увеличивает значение i, затем читает его.

Ответ 4

Поскольку вы спрашиваете о различии в цикле, я думаю, вы имеете в виду

for(int i=0; i<10; i++) 
    ...;

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

Причина, почему это не имеет значения, состоит в том, что вы не используете значение i++. Другое дело, когда вы делаете

for(int i=0, a = 0; i<10; a = i++) 
    ...;

Теперь есть разница, потому что, как указывают другие, i++ означает приращение, но оценивает предыдущее значение, но ++i означает приращение, но оценивается до i (таким образом, он будет оценивать новый стоимость). В приведенном выше случае a присваивается предыдущее значение i, а я - приращение.

Ответ 5

Возникает вопрос:

Есть ли разница в ++ я и я ++ в цикле for?

Ответ: Нет.

Почему каждый ответ должен содержать подробные объяснения о до и после приращения, когда об этом даже не спрашивают?

Этот цикл for:

for (int i = 0; // Initialization
     i < 5;     // Condition
     i++)       // Increment
{
   Output(i);
}

Переведет этот код без использования циклов:

int i = 0; // Initialization

loopStart:
if (i < 5) // Condition
{
   Output(i);

   i++ or ++i; // Increment

   goto loopStart;
}

Теперь имеет значение, если вы помещаете i++ или ++i в Приращение здесь? Нет, это не, так как возвращаемое значение операции приращения незначительно. i будет увеличиваться ПОСЛЕ выполнения кода, который находится в теле for-loop.

Ответ 6

Как показано в этом коде (см. разглашенный MSIL в комментариях), компилятор С# 3 не делает различий между я ++ и ++ я в цикле for. Если было принято значение я ++ или ++ i, то определенно будет разница (это было скомпилировано в Visutal Studio 2008/Release Build):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreOrPostIncrement
{
    class Program
    {
        static int SomethingToIncrement;

        static void Main(string[] args)
        {
            PreIncrement(1000);
            PostIncrement(1000);
            Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
        }

        static void PreIncrement(int count)
        {
            /*
            .method private hidebysig static void  PreIncrement(int32 count) cil managed
            {
              // Code size       25 (0x19)
              .maxstack  2
              .locals init ([0] int32 i)
              IL_0000:  ldc.i4.0
              IL_0001:  stloc.0
              IL_0002:  br.s       IL_0014
              IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0009:  ldc.i4.1
              IL_000a:  add
              IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0010:  ldloc.0
              IL_0011:  ldc.i4.1
              IL_0012:  add
              IL_0013:  stloc.0
              IL_0014:  ldloc.0
              IL_0015:  ldarg.0
              IL_0016:  blt.s      IL_0004
              IL_0018:  ret
            } // end of method Program::PreIncrement             
             */
            for (int i = 0; i < count; ++i)
            {
                ++SomethingToIncrement;
            }
        }

        static void PostIncrement(int count)
        {
            /*
                .method private hidebysig static void  PostIncrement(int32 count) cil managed
                {
                  // Code size       25 (0x19)
                  .maxstack  2
                  .locals init ([0] int32 i)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  IL_0002:  br.s       IL_0014
                  IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0009:  ldc.i4.1
                  IL_000a:  add
                  IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0010:  ldloc.0
                  IL_0011:  ldc.i4.1
                  IL_0012:  add
                  IL_0013:  stloc.0
                  IL_0014:  ldloc.0
                  IL_0015:  ldarg.0
                  IL_0016:  blt.s      IL_0004
                  IL_0018:  ret
                } // end of method Program::PostIncrement
             */
            for (int i = 0; i < count; i++)
            {
                SomethingToIncrement++;
            }
        }
    }
}

Ответ 7

Один (++ i) является преинкрементным, один (i ++) является постинкрестностью. Разница заключается в том, какое значение немедленно возвращается из выражения.

// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1

Edit: Woops, полностью игнорирует сторону цикла. Нет фактической разницы для циклов, когда это "шаг" (для (...;...;)), но он может вступить в игру в других случаях.

Ответ 8

Вот пример Java-образца и байт-код, post- и preIncrement не показывают разницы в Bytecode:

public class PreOrPostIncrement {

static int somethingToIncrement = 0;

public static void main(String[] args) {
    final int rounds = 1000;
    postIncrement(rounds);
    preIncrement(rounds);
}

private static void postIncrement(final int rounds) {
    for (int i = 0; i < rounds; i++) {
        somethingToIncrement++;
    }
}

private static void preIncrement(final int rounds) {
    for (int i = 0; i < rounds; ++i) {
        ++somethingToIncrement;
    }
}

}

И теперь для байтового кода (javap -private -c PreOrPostIncrement):

public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;

static {};
Code:
0:  iconst_0
1:  putstatic   #10; //Field somethingToIncrement:I
4:  return

public PreOrPostIncrement();
Code:
0:  aload_0
1:  invokespecial   #15; //Method java/lang/Object."<init>":()V
4:  return

public static void main(java.lang.String[]);
Code:
0:  sipush  1000
3:  istore_1
4:  sipush  1000
7:  invokestatic    #21; //Method postIncrement:(I)V
10: sipush  1000
13: invokestatic    #25; //Method preIncrement:(I)V
16: return

private static void postIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

private static void preIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

}

Ответ 9

Нет разницы, если вы не используете значение после инкремента в цикле.

for (int i = 0; i < 4; ++i){
cout<<i;       
}
for (int i = 0; i < 4; i++){
cout<<i;       
}

Оба цикла будут печатать 0123.

Но разница возникает, когда вы используете значение после инкремента/уменьшения в вашем цикле, как показано ниже:

Pre Increment Loop:

for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";       
cout<<k<<" "; 
}

Вывод: 0 0 1 1 2 2 3 3

Поступающий цикл:

for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";       
cout<<k<<" "; 
}

Вывод: 0 0 1 0 2 1 3 2

Я надеюсь, что разница будет очевидна, если сравнить результат. Здесь указывается, что приращение/декремент всегда выполняется в конце цикла for, и, следовательно, результаты могут быть объяснены.

Ответ 10

Да, есть. Разница заключается в возвращаемом значении. Возвращаемое значение "++ i" будет значением после увеличения i. Возврат "i ++" будет значением перед приращением. Это означает, что код выглядит следующим образом:

int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.

Следовательно, a будет 2, а b и c будут равны 1.

Я мог бы переписать код следующим образом:

int a = 0; 

// ++a;
a = a + 1; // incrementing first.
b = a; // setting second. 

// a++;
c = a; // setting first. 
a = a + 1; // incrementing second. 

Ответ 11

В обоих случаях нет никакой реальной разницы: "i" будет увеличиваться на 1.

Но есть разница, когда вы используете его в выражении, например:

int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3

Ответ 12

В ++ и я ++ существует больше, чем циклов и различий в производительности. ++ я возвращает значение l, а я ++ возвращает r-значение. Исходя из этого, вы можете сделать много вещей (++ i), но не (i ++).

1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:

T& operator ++ ( )
{
   // logical increment
   return *this;
}

const T operator ++ ( int )
{
    T temp( *this );
    ++*this;
    return temp;
}

Ответ 13

В javascript из-за следующего я ++ может быть лучше использовать:

var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.

В то время как массивы (я думаю, все) и некоторые другие функции и вызовы используют 0 в качестве отправной точки, вам нужно будет установить я в -1, чтобы заставить цикл работать с массивом при использовании ++ i.

При использовании я ++ следующее значение будет использовать увеличенное значение. Вы могли бы сказать, что я ++ - это способ подсчета людей, потому что вы можете начать с 0.

Ответ 14

Это пугает мой разум, почему люди могут писать выражение increment в for-loop как я ++.

В for-loop, когда третий компонент представляет собой простой оператор increment, как в

for (i=0; i<x; i++)  

или

for (i=0; i<x; ++i)   

нет никакой разницы в результирующих исполнениях.

Ответ 15

Как @Jon B говорит, что нет никакой разницы в цикле for.

Но в цикле while или do...while вы можете найти некоторые отличия, если вы делаете сравнение с ++i или i++

while(i++ < 10) { ... } //compare then increment

while(++i < 10) { ... } //increment then compare

Ответ 16

Для петель может быть разница. Это практическое применение post/pre-increment.

        int i = 0;
        while(i++ <= 10) {
            Console.Write(i);
        }
        Console.Write(System.Environment.NewLine);

        i = 0;
        while(++i <= 10) {
            Console.Write(i);
        }
        Console.ReadLine();

В то время как первый имеет значение 11 и цикл 11 раз, второй - нет.

В основном это довольно удобно использовать в то время как (x-- > 0); - - Loop для итерации, например, всех элементов массива (исключая здесь foreach-constructs).

Ответ 17

Они оба увеличивают число. ++i эквивалентно i = i + 1.

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

int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a = 

Отметьте эту ссылку.

Ответ 18

Да, существует разница между ++i и i++ в цикле for, хотя в необычных случаях использования; когда переменная цикла с оператором increment/decment используется в блоке for или внутри тестового выражения цикла или с одной из переменных цикла. Нет, это не просто синтаксис.

Поскольку i в коде означает вычисление выражения i, и оператор не означает оценку, а просто операцию;

  • ++i означает значение приращения i на 1, а затем оценивает i,
  • i++ означает оценку i и более позднего значения приращения i на 1.

Итак, то, что получается из каждых двух выражений, отличается тем, что оценивается в каждом из них. Все те же для --i и i--

Например:

let i = 0

i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2

В необычных случаях использования, однако следующий пример звучит полезно или не имеет значения, он показывает разницу

for(i=0, j=i; i<10; j=++i){
    console.log(j, i)
}

for(i=0, j=i; i<10; j=i++){
    console.log(j, i)
}

Ответ 19

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

Кроме того, в c++, как правило, наиболее безопасно использовать форму предварительного приращения (++i), поскольку ее легче оптимизировать. (Скотт Лэнгэм избил меня до этого лакомого кусочка. Проклятье, Скотт)

Ответ 20

Я не знаю других языков, но в Java ++ i является приращением префикса , что означает: увеличение i на 1, а затем используйте новое значение я в выражении, в котором находится i, а я ++ - приращение postfix, что означает следующее: используйте текущее значение i в выражении, а затем увеличьте его на 1. Пример:

public static void main(String [] args){

    int a = 3;
    int b = 5;
    System.out.println(++a);
    System.out.println(b++);
    System.out.println(b);

} и выход:

  • 4
  • 5
  • 6

Ответ 21

i ++; ++ i; оба они похожи, так как они не используются в выражении.

class A {

     public static void main (String []args) {

     int j = 0 ;
     int k = 0 ;
     ++j;
     k++;
    System.out.println(k+" "+j);

}}

prints out :  1 1