Есть ли разница в ++i
и i++
в for
цикле? Это просто синтаксис?
Есть ли разница в ++i
и i++
в for
цикле? Это просто синтаксис?
Ответы:
А ++ известен как постфикс.
добавить 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, как показано ниже, это не имеет значения, поскольку вы не используете возвращаемое значение 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++) { }
Предварительное увеличение ++ 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 ++ предварительное увеличение обычно предпочтительнее, когда вы можете использовать любой из них.
Это потому, что если вы используете постинкремент, компилятору может потребоваться сгенерировать код, который создает дополнительную временную переменную. Это связано с тем, что как предыдущие, так и новые значения увеличиваемой переменной должны храниться где-то, поскольку они могут понадобиться где-то еще в вычисляемом выражении.
Так что, по крайней мере, в C ++ может быть разница в производительности, которая определяет ваш выбор.
Это в основном проблема только в том случае, если приращиваемая переменная является пользовательским типом с переопределенным оператором ++. Для примитивных типов (int и т. Д.) Нет разницы в производительности. Но в качестве ориентира стоит придерживаться оператора предварительного увеличения, если только оператор пост-увеличения не является тем, что требуется.
Здесь есть еще несколько дискуссий:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
В C ++, если вы используете STL, вы можете использовать циклы for с итераторами. В основном они имеют переопределенные операторы ++, поэтому придерживаться предварительного увеличения - хорошая идея. Тем не менее, компиляторы становятся все умнее, а более новые могут выполнять оптимизацию, что означает, что нет разницы в производительности, особенно если тип приращения определен встроенным в заголовочном файле (как это часто бывает с реализациями STL), так что компилятор может видеть, как метод реализован и может знать, какие оптимизации безопасно выполнить. Несмотря на это, вероятно, все еще стоит придерживаться предварительного увеличения, поскольку циклы выполняются много раз, и это означает, что небольшое ухудшение производительности может вскоре усилиться.
В других языках, таких как C #, где оператор ++ не может быть перегружен, разницы в производительности нет. Используемые в цикле для продвижения переменной цикла, операторы до и после приращения эквивалентны.
Исправление: перегрузка ++ в C # разрешена. Тем не менее, кажется, что по сравнению с C ++, в C # вы не можете перегружать предварительную и последующую версии независимо друг от друга. Итак, я бы предположил, что если результат вызова ++ в 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 увеличивает значение i, затем читает его.
++i
и i++
выполняют одинаковые операции в одинаковом порядке: создайте временную копию i
; увеличить временное значение, чтобы создать новое значение (не переопределять временное значение); сохранить новое значение в i
; теперь, если это ++i
результат, возвращается новое значение; если это i++
результат, возвращается временная копия. Более подробный ответ здесь: stackoverflow.com/a/3346729/3330348
Вопрос в том:
Есть ли разница в ++ i и i ++ в цикле 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.
Поскольку вы спрашиваете о разнице в цикле, я думаю, вы имеете в виду
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 увеличивается.
Как показывает этот код (см. 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
Изменить: Woops, полностью игнорируется сторона цикла вещей. Фактически нет разницы в циклах for, когда это часть 'step' (for (...; ...;)), но она может вступить в действие в других случаях.
Нет разницы, если вы не используете значение после приращения в цикле.
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 и, следовательно, результаты могут быть объяснены.
Вот пример Java и Байт-код, post- и preIncrement не показывают различий в Байт-коде:
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
}
Да, есть. Разница в возвращаемом значении. Возвращаемое значение «++ 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;
}
Мне непонятно, почему люди могут записывать выражение приращения в цикле for как 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
В 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
Изображение выше показывает, что FOR можно преобразовать в WHILE , поскольку в конечном итоге они имеют абсолютно одинаковый код сборки (по крайней мере, в gcc). Таким образом, мы можем разбить FOR на пару частей, чтобы осуществить то, что он делает.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
равно WHILE версии
i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}
Это означает, что вы можете использовать FOR как простую версию WHILE :
Первый аргумент FOR (int i) выполняется снаружи перед циклом.
Третий аргумент FOR (i ++ или ++ i) выполняется внутри последней строки цикла.
TL: DR: независимо от того ,
i++
или++i
мы знаем , что , когда они являются автономными, они не делают никакой разницы , но +1 на себя.В школе они обычно преподают способ i ++, но есть также много людей, которые предпочитают способ ++ i по нескольким причинам .
ПРИМЕЧАНИЕ. В прошлом i ++ очень мало влиял на производительность, так как он не только добавляет один плюс, но также сохраняет исходное значение в регистре. Но сейчас это не имеет значения, так как компилятор делает плюс одну часть одинаковой.
Там может быть разница для петель. Это практическое применение 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
цикле, хотя в необычных случаях использования; когда переменная цикла с оператором увеличения / уменьшения используется в блоке 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++
обычно безопаснее использовать форму pre-increment ( ++i
), поскольку ее легче оптимизировать. (Скотт Лэнгхэм избил меня до этого лакомого кусочка . Проклинаю тебя, Скотт)
Я не знаю, для других языков, но в Java ++ i - приращение префикса, которое означает: увеличьте i на 1, а затем используйте новое значение i в выражении, в котором я находится, а 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);
} и вывод: