Разница между I++ и ++I в цикле?
есть ли разница в ++i
и i++
на for
петли? Это просто синтаксис?
21 ответов
a++ известен как postfix.
add 1 to a, возвращает старое значение.
++a известен как префикс.
add 1 to 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++, pre-increment обычно предпочтительнее, где вы можете использовать либо.
это потому, что если вы используете 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, а затем читает его.
поскольку вы спрашиваете о разнице в цикле, я думаю, вы имеете в виду
for(int i=0; i<10; i++)
...;
в этом случае у вас нет разницы в большинстве языков: цикл ведет себя одинаково независимо от того, пишете ли вы i++
и ++i
. В C++, вы можете написать свои собственные версии операторов++, и вы можете определить отдельные значения для них, если i
имеет определенный пользователем тип (например, ваш собственный класс).
причина, почему это не имеет значения выше, потому что вы не используйте значение i++
. Другое дело, когда вы делаете
for(int i=0, a = 0; i<10; a = i++)
...;
есть и разница, потому что, как отмечают другие,i++
означает increment, но оцените Предыдущее значение, а ++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-loop-body.
Как показывает этот код (см. разбитый 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-loop, когда 3-й компонент является простым оператором инкремента, как в
for (i=0; i<x; i++)
или
for (i=0; i<x; ++i)
нет никакой разницы в результате казней.
As @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
цикл, хотя и в необычных случаях использования; когда используется переменная цикла с оператором инкремента/декремента в блоке или в пределах цикла тестового выражения или С одной переменной цикла. Нет, это не просто синтаксис.
As 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
), потому что он более легко оптимизирован. (Скотт Лэнгэм опередите меня в этом лакомый кусочек. Будь ты проклят, Скотт!--6-->
Я не знаю для других языков, но в Java ++i - это префикс increment что означает: увеличение Я на 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
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