В чем разница между использованием ++i и i++ в языке C и что следует использовать в блоке приращения цикла for?





++i увеличивает значение на единицу, а затем возвращает его.
i++ возвращает значение, а затем увеличивает его.
Это тонкая разница.
Для цикла for используйте ++i, так как он немного быстрее. i++ создаст дополнительную копию, которую просто выбрасывают.
Я не знаю ни одного компилятора, в котором это имеет значение, по крайней мере, для целых чисел.
Это не быстрее. Значения игнорируются (действует только побочный эффект), и компилятор может / сгенерирует точно такой же код.
++i увеличит значение i, а затем вернет увеличенное значение.
i = 1;
j = ++i;
(i is 2, j is 2)
i++ увеличит значение i, но вернет исходное значение, которое i удерживал до увеличения.
i = 1;
j = i++;
(i is 2, j is 1)
Для петли for работает любой из них. ++i кажется более распространенным, возможно потому, что он используется в K&R.
В любом случае следуйте рекомендациям «предпочитайте ++i, а не i++», и вы не ошибетесь.
Есть пара замечаний по поводу эффективности ++i и i++. В любом компиляторе не студенческого проекта разницы в производительности не будет. Вы можете убедиться в этом, посмотрев на сгенерированный код, который будет идентичным.
Интересен вопрос эффективности ... вот моя попытка ответить: Есть ли разница в производительности между i ++ и ++ i в C?
Как отмечает @OnFreund, для объекта C++ он отличается, поскольку operator++() - это функция, и компилятор не может знать, как оптимизировать создание временного объекта для хранения промежуточного значения.
Не выдержит ли этот эффект повторного запуска цикла при достижении конечного условия? Например, for(int i=0; i<10; i++){ print i; } не будет отличаться от for(int i=0; i<10; ++i){ print i; }. Насколько я понимаю, некоторые языки дадут вам разные результаты в зависимости от того, какой вы используете.
jonnyflash, оба будут работать одинаково, поскольку приращение i и печать находятся в разных операторах. Так должно быть в любом языке, поддерживающем стиль C++. Единственная разница между ++ i и i ++ будет заключаться в использовании значения операции в одном и том же операторе.
Итак, если бы вы увеличивали внутри цикла, а не в составном операторе for, это имело бы значение, верно? Такие как for(int i=0; i<10){ print i; ++i;
нет, поскольку печать и приращение находятся в разных операторах, приращение может быть либо ++ i, либо i ++. Если бы вместо этого у вас были print ++ i и print i ++, результаты были бы другими.
Поскольку в большинстве случаев они производят идентичный код, я предпочитаю i++, потому что он имеет форму «операнд-оператор», как присвоение «операнд-оператор-значение». Другими словами, целевой операнд находится в левой части выражения, как и в операторе присваивания.
@MarkHarrison, он будет работать одинаково не потому, что i++ и print i находятся в разных операторах, а потому, что i++; и i<10. Замечание @jonnyflash не так уж неуместно. Предположим, у вас есть for(int i=0; i++<10){ print i; } и for(int i=0; ++i<10){ print i; }. Они будут работать по-другому, как описано в первом комментарии @johnnyflash.
++ i означает увеличение значения, а затем использование. i ++ означает использовать значение, а затем увеличивать его.
@ARUN i++ означает увеличение значения и eval как значение прежний для увеличения. Отличается сам результат eval, а не то, когда происходит приращение. Результат eval до приращения находится после приращения, результат eval после приращения находится перед приращением, но независимо от того, какое приращение происходит до того, как будет получен результат вычисления имеется в наличии. Посмотреть живой пример демонстрирует это.
@sam, потому что в типичном цикле for нет побочного эффекта (например, присваивания) в части ++ i.
Я сомневался в этом ответе и разместил вопрос. Я думаю, что пока обсуждается этот ответ, вы должны проверить его и опубликовать то, что вы на самом деле имели в виду: stackoverflow.com/questions/35643963/…. Несмотря на то, что он отмечен как обман, многие люди голосуют за его повторное открытие, и в настоящее время было проведено 3 повторных голосования. Я не думаю, что это обман, и было бы полезно, если бы вы могли развеять мои сомнения.
Я в основном использую --i и i-- в цикле do.. while. В первом случае 0 не будет оцениваться внутри цикла, а во втором - будет.
«Предпочитайте ++ i над i ++ в циклах for». Это противоречит каждому современному руководству по стилю, которое я когда-либо видел.
Не выдержит ли этот эффект циклов времени? Некоторые языки определенно обрабатывают это по-разному, меня учили, что практика использования стиля C++. ++ был постоянным методом в колледже, но это было 20 лет назад ... правильно ли учитывается итерация цикла? J=100; I=1;While (J*++I <=500){Print Do something for Five iterations! Currently I = I }; Print Oh Good! Clearly the result I need is I ?
Причина, по которой ++iможет немного быстрее, чем i++, заключается в том, что i++ может потребовать локальную копию значения i, прежде чем оно будет увеличено, в то время как ++i никогда этого не делает. В некоторых случаях некоторые компиляторы оптимизируют его, если это возможно ... но это не всегда возможно, и не все компиляторы делают это.
Я стараюсь не слишком полагаться на оптимизацию компиляторов, поэтому я следую совету Райана Фокса: когда я могу использовать оба, я использую ++i.
-1 за ответ C++ на вопрос C. Когда вы пишете оператор i, не существует более "локальной копии" значения 1;, чем имеется значение 1.
Пожалуйста, не беспокойтесь о «эффективности» (на самом деле, скорости), какая из них выше. В наши дни у нас есть компиляторы, которые заботятся об этом. Используйте то, что имеет смысл использовать, исходя из того, что более четко показывает ваше намерение.
что, я надеюсь, означает «используйте префикс (inc | dec) rement, если вам действительно не нужно старое значение до (inc | dec), что очень мало людей делают, но которое используется в ошеломляющей части предполагаемых учебных материалов, создавая культ груза среди пользователей постфикса, которые даже не знаю что это» ..!
Я не уверен, что «компиляторы в наши дни ... позаботятся об этих вещах» универсально верно. В пользовательском operator++(int) (версия с постфиксом) код в значительной степени должен создать временное, которое будет возвращено. Вы уверены, что компиляторы всегда могут это оптимизировать?
Эффективный результат использования любого из них в цикле идентичен. Другими словами, в обоих случаях цикл будет делать одно и то же.
С точки зрения эффективности, выбор i ++ вместо ++ i может повлечь за собой штраф. С точки зрения спецификации языка, использование оператора постинкремента должно создать дополнительную копию значения, на которое действует оператор. Это могло быть источником дополнительных операций.
Однако вы должны рассмотреть две основные проблемы с предыдущей логикой.
Современные компиляторы великолепны. Все хорошие компиляторы достаточно умны, чтобы понимать, что они видят целочисленное приращение в цикле for, и оптимизируют оба метода для получения одного и того же эффективного кода. Если использование постинкремента вместо прединкремента фактически приводит к тому, что ваша программа работает медленнее, тогда вы используете компилятор ужасный.
С точки зрения сложности операций, эти два метода (даже если копирование фактически выполняется) эквивалентны. Количество инструкций, выполняемых внутри цикла, должно значительно преобладать над количеством операций в операции приращения. Следовательно, в любом цикле значительного размера штраф метода приращения будет значительно перекрыт выполнением тела цикла. Другими словами, вам гораздо лучше беспокоиться об оптимизации кода в цикле, а не об инкременте.
На мой взгляд, все сводится к предпочтениям стиля. Если вы думаете, что предварительное приращение более читабельно, используйте его. Лично я предпочитаю постинкремент, но, вероятно, потому, что этому меня учили до того, как я узнал что-либо об оптимизации.
Это типичный пример преждевременной оптимизации, и подобные проблемы могут отвлечь нас от серьезных проблем в дизайне. Однако это по-прежнему хороший вопрос, потому что нет единообразия в использовании или консенсуса в отношении «лучших практик».
Я полагаю, вы теперь понимаете разницу в семантике (хотя, честно говоря, мне интересно, почему люди спрашивают, что означает оператор X, вопросы о переполнении стека, а не о чтении, ну знаете, книгу или веб-учебник или что-то в этом роде.
Но в любом случае, что касается того, какой из них использовать, игнорируйте вопросы производительности, которые вряд ли важно даже в C++. Это принцип, который вы должны использовать при принятии решения что использовать:
Скажите, что вы имеете в виду в коде.
Если вам не нужно значение до приращения в вашем операторе, не используйте эту форму оператора. Это незначительная проблема, но если вы не работаете с руководством по стилю, которое запрещает его версия в пользу другой (также известной как руководство по стилю), вы должны использовать форма, которая наиболее точно выражает то, что вы пытаетесь сделать.
QED, используйте версию до инкремента:
for (int i = 0; i != X; ++i) ...
я ++ известен как Пост инкремент, тогда как ++ я называется Pre Increment.
i++
i++ - это пост-инкремент, потому что он увеличивает значение i на 1 после завершения операции.
Давайте посмотрим на следующий пример:
int i = 1, j;
j = i++;
Здесь значение j = 1, но i = 2. Здесь значение i будет сначала присвоено j, затем i будет увеличен.
++i
++i является предварительным инкрементом, потому что он увеличивает значение i на 1 перед операцией.
Это означает, что j = i; будет выполняться после i++.
Давайте посмотрим на следующий пример:
int i = 1, j;
j = ++i;
Здесь значение j = 2, но i = 2. Здесь значение i будет присвоено j после приращения ii.
Точно так же ++i будет выполняться до j=i;.
На ваш вопрос что следует использовать в блоке приращения цикла for? ответ: вы можете использовать любой ... не имеет значения. Он выполнит ваш цикл for с таким же номером. раз.
for(i=0; i<5; i++)
printf("%d ",i);
И
for(i=0; i<5; ++i)
printf("%d ",i);
Оба цикла производят одинаковый результат. т.е. 0 1 2 3 4.
Имеет значение только то, где вы его используете.
for(i = 0; i<5;)
printf("%d ",++i);
В этом случае на выходе будет 1 2 3 4 5.
Инициализация переменных после префикса и пост-исправления помогает понять. Спасибо.
a = i ++ означает, что a содержит текущее значение i a = ++ i означает, что a содержит увеличенное значение i
Это неточный ответ. a = i++; означает, что значение, сохраненное в a, будет значением i до приращения, но «без приращения» означает, что i не увеличивается, что совершенно неверно - i увеличивается, но значение выражения является значением до приращения .
i++: в этом сценарии сначала присваивается значение, а затем происходит приращение.
++i: в этом сценарии сначала выполняется приращение, а затем присваивается значение
Ниже представлена визуализация изображения, а также вот хорошее практическое видео, который демонстрирует то же самое.

Как можно увеличить то, что не назначено?
@kouty Вы можете увеличивать регистр, не назначенный переменной.
Вскоре:
++i и i++ работают одинаково, если вы не записываете их в функции. Если вы используете что-то вроде function(i++) или function(++i), вы можете увидеть разницу.
function(++i) говорит, что первое приращение i на 1, после этого помещает i в функцию с новым значением.
function(i++) говорит, что сначала нужно добавить i в функцию, а затем увеличить i на 1.
int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now
На самом деле разница не связана с вызовами функций (и вы можете заметить разницу, не выполняя вызовов функций). Есть разница между int j = ++i; и int k = i++;, даже если не задействован вызов функции.
++i: пре-инкремент, другой пост-инкремент.
i++: получает элемент и затем увеличивает его.
++i: увеличивает i, а затем возвращает элемент.
Пример:
int i = 0;
printf("i: %d\n", i);
printf("i++: %d\n", i++);
printf("++i: %d\n", ++i);
Выход:
i: 0
i++: 0
++i: 2
Вот пример, чтобы понять разницу
int i=10;
printf("%d %d",i++,++i);
вывод: 10 12/11 11 (в зависимости от порядка вычисления аргументов функции printf, который зависит от компилятора и архитектуры)
Объяснение:
i++-> i печатается, а затем увеличивается. (Печать 10, но i станет 11)
++i-> i увеличивает значение и печатает значение. (Отпечатков 12, и значение i также 12)
Это вызывает неопределенное поведение, поскольку между i++ и ++i нет точки последовательности.
@Lundin - это правильно, хотя LHS, RHS запятой имеют точку последовательности между ними, но 2 выражения все еще не упорядочены друг относительно друга
++i (операция префикса): увеличивает, а затем присваивает значение
(например): int i = 5, int b = ++i
В этом случае 6 сначала присваивается b, а затем увеличивается до 7 и так далее.
i++ (операция Postfix): присваивает и затем увеличивает значение
(например): int i = 5, int b = i++
В этом случае 5 сначала присваивается b, а затем увеличивается до 6 и так далее.
Случай цикла for: в основном используется i++, потому что обычно мы используем начальное значение i перед увеличением цикла for. Но в зависимости от логики вашей программы она может отличаться.
The Main Difference is
- i++ Post(After Increment) and
++i Pre (Before Increment)
- post if
i =1the loop increments like1,2,3,4,n- pre if
i =1the loop increments like2,3,4,5,n
Разницу можно понять с помощью этого простого кода C++ ниже:
int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;
Pre-crement означает приращение в той же строке. Постинкремент означает приращение после выполнения строки.
int j=0;
System.out.println(j); //0
System.out.println(j++); //0. post-increment. It means after this line executes j increments.
int k=0;
System.out.println(k); //0
System.out.println(++k); //1. pre increment. It means it increments first and then the line executes
Когда дело доходит до операторов OR, AND, становится интереснее.
int m=0;
if ((m == 0 || m++ == 0) && (m++ == 1)) { //false
/* in OR condition if first line is already true then compiler doesn't check the rest. It is technique of compiler optimization */
System.out.println("post-increment "+m);
}
int n=0;
if ((n == 0 || n++ == 0) && (++n == 1)) { //true
System.out.println("pre-increment "+n); //1
}
В массиве
System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 } ;
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); //12
jj = a[1]++; //12
System.out.println(a[1]); //a[1] = 13
mm = a[1];//13
System.out.printf ( "\n%d %d %d\n", ii, jj, mm ) ; //12, 12, 13
for (int val: a) {
System.out.print(" " +val); //55, 13, 15, 20, 25
}
В C++ post / pre-приращение переменной указателя
#include <iostream>
using namespace std;
int main() {
int x=10;
int* p = &x;
std::cout<<"address = "<<p<<"\n"; //prints address of x
std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
std::cout<<"address = "<<&x<<"\n"; //prints address of x
std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}
Следующий фрагмент кода C иллюстрирует разницу между операторами инкремента и декремента до и после:
int i;
int j;
Операторы увеличения:
i = 1;
j = ++i; // i is now 2, j is also 2
j = i++; // i is now 3, j is 2
Они оба увеличивают число. ++i эквивалентен i = i + 1.
i++ и ++i очень похожи, но не совсем одинаковы. Оба увеличивают число, но ++i увеличивает число перед вычислением текущего выражения, тогда как i++ увеличивает число после вычисления выражения.
Пример:
int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3
Этот небольшой код может помочь визуализировать разницу под другим углом, чем уже опубликованные ответы:
int i = 10, j = 10;
printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);
printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);
Результат:
//Remember that the values are i = 10, and j = 10
i is 10
i++ is 10 //Assigns (print out), then increments
i is 11
j is 10
++j is 11 //Increments, then assigns (print out)
j is 11
Обратите внимание на ситуации до и после.
Что касается того, какой из них следует использовать в блоке приращения цикла for, я думаю, что лучшее, что мы можем сделать для принятия решения, - это использовать хороший пример:
int i, j;
for (i = 0; i <= 3; i++)
printf (" > iteration #%i", i);
printf ("\n");
for (j = 0; j <= 3; ++j)
printf (" > iteration #%i", j);
Результат:
> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3
Не знаю, как вы, но я не вижу разницы в его использовании, по крайней мере, в цикле for.
Отличный ответ. Другие написали то же самое, что и копипаст, или более сложные коды. Мы все знаем (при условии хорошего знакомства с программированием) термины постфикса и префикса, но то, как они будут себя вести, можно действительно понять с помощью цикла for.
Вы можете думать о внутреннем преобразовании этого как несколько заявлений;
i++;
Вы можете думать об этом как
i;
i = i+1;
++i;
Вы можете думать об этом как
i = i+i;
i;
Единственная разница - это порядок операций между приращением переменной и значением, возвращаемым оператором.
Этот код и его вывод объясняют разницу:
#include<stdio.h>
int main(int argc, char* argv[])
{
unsigned int i=0, a;
printf("i initial value: %d; ", i);
a = i++;
printf("value returned by i++: %d, i after: %d\n", a, i);
i=0;
printf("i initial value: %d; ", i);
a = ++i;
printf(" value returned by ++i: %d, i after: %d\n",a, i);
}
Результат:
i initial value: 0; value returned by i++: 0, i after: 1
i initial value: 0; value returned by ++i: 1, i after: 1
Таким образом, ++i возвращает значение после увеличения, а i++ возвращает значение до его увеличения. В конце в обоих случаях значение i будет увеличено.
Другой пример:
#include<stdio.h>
int main ()
int i=0;
int a = i++*2;
printf("i=0, i++*2=%d\n", a);
i=0;
a = ++i * 2;
printf("i=0, ++i*2=%d\n", a);
i=0;
a = (++i) * 2;
printf("i=0, (++i)*2=%d\n", a);
i=0;
a = (++i) * 2;
printf("i=0, (++i)*2=%d\n", a);
return 0;
}
Выход:
i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2
Различия очевидны, когда возвращаемое значение присваивается другой переменной или когда приращение выполняется в сочетании с другими операциями, в которых применяется приоритет операций (i++*2 отличается от ++i*2, но (i++)*2 и (++i)*2 возвращают то же значение) во многих случаях они взаимозаменяемы. . Классический пример - синтаксис цикла for:
for(int i=0; i<10; i++)
имеет тот же эффект
for(int i=0; i<10; ++i)
Чтобы не путать эти два оператора, я принял это правило:
Свяжите позицию оператора ++ относительно переменной i с порядком операции ++ относительно присваивания
Другими словами:
++передi означает, что приращение должно выполняться при назначении перед;++послеi означает, что приращение должно выполняться. Назначение после:
Не уверен, что исходный плакат интересен, но в C++ разница в производительности может быть значительной, поскольку создание временного объекта может быть дорогостоящим для определенного пользователем типа.