Разница между I++ и ++I в цикле?
есть ли разница в ++i
и i++
на for
петли? Это просто синтаксическая вещь?
21 ответ:
a++ известен как постфикс.
добавить 1 к a, возвращает старое значение.
++a известен как префикс.
добавить 1 к a, возвращает новое значение.
C#:
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
петли зависят от того, какой тип инкремента вы используете. С for loops, как показано ниже, это не имеет значения, поскольку вы не используете возвращаемое значение 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++) { }
Pre-increment ++i увеличивает значение i и вычисляет новое увеличенное значение.
int i = 3; int preIncrementResult = ++i; Assert( preIncrementResult == 4 ); Assert( i == 4 );
пост-инкремент i++ увеличивает значение i и вычисляет исходное значение без увеличения.
int i = 3; int postIncrementResult = i++; Assert( postIncrementtResult == 3 ); Assert( i == 4 );
в C++ предварительное приращение обычно предпочтительно там, где вы можете использовать либо.
это связано с тем, что если вы используете post-increment, это может потребовать от компилятора генерировать код, который создает дополнительная временная переменная. Это потому, что обе предыдущие и новые значения переменной приращения должны быть проведены где-то, потому что они могут быть нужны в другом месте в выражении оценки.
таким образом, в C++, по крайней мере, может быть разница в производительности, которая определяет ваш выбор того, что использовать.
это, в основном, только проблема, когда переменная приращения-это определяемый пользователем тип с переопределенным оператором++. Для примитивных типов (int, и т. д.) нет никакой разницы в производительности. Но стоит придерживаться оператора pre-increment в качестве руководства, если оператор post-increment определенно не является тем, что требуется.
есть еще несколько обсуждений here:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htmВ C++ если вы используете STL, то вы можете использовать для циклов с итераторами. Они в основном имеют переопределенные операторы++, поэтому прилипают для предварительного приращения это хорошая идея. Однако компиляторы все время становятся умнее, и более новые могут выполнять оптимизации, которые означают, что нет разницы в производительности, особенно если инкрементируемый тип определен в заголовочном файле (как часто бывают реализации STL), чтобы компилятор мог видеть, как реализуется метод, а затем знать, какие оптимизации безопасны для выполнения. Тем не менее, это, вероятно, все еще стоит придерживаться предварительного приращения, потому что циклы выполняются много раз и это означает, что небольшой штраф за производительность может вскоре усилиться.
в других языках, таких как C#, где оператор ++ не может быть перегружен, нет разницы в производительности. Используемые в цикле для продвижения переменной цикла операторы pre и post increment эквивалентны.
исправление: перегрузка ++ в C# разрешена. Кажется, однако, что по сравнению с C++, в c# вы не можете перегружать pre и post версии независимо. Итак, я бы предположил что если результат вызова ++ в C# не назначен переменной или не используется как часть сложного выражения, то компилятор уменьшит предварительные и последующие версии ++ до кода, который выполняет эквивалентно.
В C# нет никакой разницы при использовании в цикле for.
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
выводит то же самое как
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
как указывали другие, при использовании в целом i++ и ++у меня есть тонкая, но значительная разница:
int i = 0; Console.WriteLine(i++); // Prints 0 int j = 0; Console.WriteLine(++j); // Prints 1
i++ считывает значение i, а затем увеличивает его.
Я++увеличивает значение i, а затем читает его.
так как вы спрашиваете о разнице в цикле, я думаю, вы имеете в виду
for(int i=0; i<10; i++) ...;
в этом случае у вас нет разницы в большинстве языков: цикл ведет себя одинаково независимо от того, пишете ли вы
i++
и++i
. В C++, вы можете написать свои собственные версии операторов++, и вы можете определить отдельные значения для них, еслиi
имеет определенный пользователем тип (например, ваш собственный класс).причина, почему это не имеет значения выше, потому что вы не используйте значение
i++
. Другое дело, когда вы делаетеfor(int i=0, a = 0; i<10; a = i++) ...;
есть и разница, потому что, как указывают другие,
i++
означает инкремент, но оценить до предыдущего значения, а++i
означает инкремент, но оценить кi
(таким образом, он будет оценивать новое значение). В приведенном выше случае,a
присваивается Предыдущее значение i, в то время как i увеличивается.
вопрос:
есть ли разница в ++i и I++ в цикле for?
ответ: нет.
почему каждый другой ответ должен входить в подробные объяснения о приращении до и после, когда это даже не спрашивается?
Это for-loop:
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.
Как показывает этот код (см. разбитый MSIL в комментариях), компилятор C# 3 не делает различий между i++ и ++i в цикле for. Если бы значение i++ или ++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++; } } } }
один (++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, полностью проигнорировал сторону цикла вещей. Нет никакой фактической разницы в циклах for, когда это часть " шаг " (for (...; ...; )), но он может вступить в игру и в других случаях.
вот Java-пример и байт-код, пост-и преинкремент не показывают никакой разницы в байт-коде:
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 }
нет никакой разницы, если вы не используете значение после инкремента в цикле.
for (int i = 0; i < 4; ++i){ cout<<i; } for (int i = 0; i < 4; i++){ cout<<i; }
обе петли будут печатать 0123.
но разница возникает, когда вы используете значение после инкремента / декремента в цикле, как показано ниже:
Цикл Предварительного Приращения:
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 и, следовательно, результаты могут быть объяснены.
Да, есть. Разница заключается в возвращаемом значении. Возвращаемое значение "++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.
нет фактической разницы в обоих случаях '
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
в ++i и i++ есть больше, чем циклы и различия в производительности. ++i возвращает l-значение, а i++ возвращает 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; }
в javascript из-за следующего i++ может быть лучше использовать:
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 в качестве отправной точки, вам нужно будет установить i в -1, чтобы цикл работал с массивом при использовании ++i.
при использовании i++ следующее значение будет использовать увеличенное значение. Можно сказать i++ это то, как люди считают, потому что вы можете начать с 0.
меня поражает, почему так могут люди писать выражение инкремента в for-loop как i++.
в цикле for, когда 3-й компонент является простым оператором инкремента, как в
for (i=0; i<x; i++)
или
for (i=0; i<x; ++i)
нет никакой разницы в результате казней.
как @Jon B говорит, нет никакой разницы в цикле for.
а в
while
илиdo...while
цикл, вы можете найти некоторые различия, если вы делаете сравнение с++i
илиi++
while(i++ < 10) { ... } //compare then increment while(++i < 10) { ... } //increment then compare
там может быть разница для петель. Это практическое применение 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 раз, второй не делает.
в основном это скорее используется в простом while (x-- > 0 ) ; - - цикл для итерации, например, всех элементов массива (за исключением foreach-конструкций здесь).
они оба увеличивают число.
++i
эквивалентноi = i + 1
.
i++
и++i
очень похожи, но не одинаковы. Оба увеличивают число, но++i
увеличивает число перед вычислением текущего выражения, тогда какi++
увеличивает число после вычисления выражения.int i = 3; int a = i++; // a = 3, i = 4 int b = ++a; // b = 4, a =
Регистрация этой ссылке.
Да, есть разница между
++i
иi++
на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) }
на
i
из пользовательских типов эти операторы могут (но не должен) имеют существенно различную сематику в контексте индекса цикла, и это может (но не должно) влиять на поведение описанного цикла.кроме того, в
c++
обычно безопаснее всего использовать форму предварительного приращения (++i
), потому что он более легко оптимизируется. (Скотт Лэнгхэм опереди меня в этом лакомый кусочек. Будь ты проклят, Скотт)
Я не знаю для других языков, но в Java ++i - это префиксный инкремент что означает: увеличение Я 1, а затем использовать новое значение i в выражение, в котором Я проживает, и 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