В чем разница между ++ i и i ++?

avatar
The.Anti.9
24 августа 2008 в 05:19
1307653
22
1002

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

Источник
On Freund
24 августа 2008 в 05:57
13

Не уверен, что исходный плакат интересен, но в C ++ разница в производительности может быть значительной, поскольку создание временного объекта может быть дорогостоящим для определенного пользователем типа.

Ответы (22)

avatar
Mark Harrison
24 августа 2008 в 05:23
1251
  • ++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++() - это функция, и компилятор не может знать, как оптимизировать создание временного объекта для хранения промежуточного значения.

aVeRTRAC
16 августа 2011 в 17:58
7

Не выдержит ли этот эффект повторного запуска цикла при достижении конечного условия? Например, for(int i=0; i<10; i++){ print i; } не будет отличаться от for(int i=0; i<10; ++i){ print i; } Насколько я понимаю, некоторые языки дадут вам разные результаты в зависимости от того, какой вы используете.

Mark Harrison
16 августа 2011 в 18:44
35

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

aVeRTRAC
17 августа 2011 в 21:34
0

Итак, если бы вы увеличивали внутри цикла, а не в составном операторе for, это имело бы значение, верно? Например, for(int i=0; i<10){ print i; ++i;

Mark Harrison
18 августа 2011 в 00:46
0

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

David R Tribble
11 декабря 2012 в 16:49
20

Поскольку в большинстве случаев они производят идентичный код, я предпочитаю i++, потому что он имеет форму «операнд-оператор», а-ля присваивание «операнд-оператор-значение». Другими словами, целевой операнд находится в левой части выражения, как и в операторе присваивания.

Adam
17 апреля 2014 в 08:55
3

@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.

ARUN
23 мая 2014 в 19:02
1

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

WhozCraig
12 августа 2014 в 09:10
1

@ARUN i++ означает увеличение значения, а eval как значение , предшествующее , для увеличения. Отличается сам результат eval, а не то, когда происходит приращение. Результат eval до приращения находится после приращения, результат eval после приращения находится перед приращением, но независимо от того, какое приращение происходит до того, как результат eval станет доступным . См. Живой пример, демонстрирующий это.

Mark Harrison
24 марта 2015 в 04:57
3

@sam, потому что в типичном цикле for в части ++ i нет побочного эффекта (например, присваивания).

Ashish Ahuja
26 февраля 2016 в 06:32
0

Я сомневался в этом ответе и разместил вопрос. Я думаю, что пока идет обсуждение этого ответа, вы должны проверить его и опубликовать то, что вы на самом деле имели в виду: coderhelper.com/questions/35643963/…. Несмотря на то, что он отмечен как обман, многие люди голосуют за его повторное открытие, и в настоящее время было проведено 3 повторных голосования. Я не думаю, что это обман, и было бы полезно, если бы вы могли развеять мои сомнения.

tcop
23 декабря 2016 в 23:15
0

Я в основном использую --i и i-- в цикле do.. while. В первом случае 0 не будет оцениваться внутри цикла, а во втором - будет.

rmoro
16 марта 2018 в 03:46
1

«Предпочитайте ++ i над i ++ в циклах for». Это противоречит каждому современному руководству по стилю, которое я когда-либо видел.

Ben Personick
23 мая 2019 в 19:50
0

Не выдержит ли этот эффект циклов времени? Некоторые языки определенно обрабатывают это по-разному, меня учили, что практика использования стиля 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 ?

avatar
Talat El Beick
11 января 2022 в 18:21
0

Проще говоря, разница между ними заключается в шагах. Взгляните на изображение ниже.

enter image description here

Пример:

int i = 1;
int j = i++;

Результат j: 1

int i = 1;
int j = ++i;

Результат j: 2

Примечание: в обоих случаях значение i равно 2

avatar
Francesco Boi
27 февраля 2019 в 17:49
15

Единственное различие заключается в порядке операций между приращением переменной и значением, возвращаемым оператором.

Этот код и его выходные данные объясняют разницу:

#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 означает, что приращение должно выполняться после присвоения:
avatar
Jeet Parikh
6 августа 2018 в 09:25
2

Вы можете представить себе внутреннее преобразование этого как несколько операторов ;

  • случай 1
i++;

вы можете думать как,

i;
i = i+1;
  • случай 2
++i;

вы можете думать как,

i = i+i;
i;
avatar
carloswm85
19 февраля 2018 в 20:51
7

i ++ и ++ i

Этот небольшой код может помочь визуализировать разницу под другим углом, чем уже опубликованные ответы:

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.

Nikhil Arora
5 февраля 2021 в 13:43
1

Отличный ответ. Другие написали то же самое, что и копипаст, или более сложные коды. Мы все знаем (при условии хорошего знакомства с программированием) термины постфикса и префикса, но то, как они будут себя вести, можно действительно понять с помощью цикла for.

avatar
Usman
19 февраля 2018 в 05:04
17

Они оба увеличивают число. ++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
avatar
Nihal Reddy
1 октября 2017 в 15:58
6

Следующий фрагмент кода 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
avatar
Uddhav Gautam
29 сентября 2017 в 16:49
5

Предварительное добавление означает приращение в той же строке. Постинкремент означает приращение после выполнения строки.

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 ++ пост / предварительное приращение переменной-указателя

#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)
}
avatar
IOstream
12 сентября 2017 в 21:13
5

Разницу можно понять с помощью этого простого кода 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;
avatar
Gopinath Kaliappan
13 мая 2016 в 06:00
5

Основное отличие:

  • i ++ Post ( После увеличения ) и
  • ++ i Pre ( до приращения )

    • опубликовать, если i =1 цикл увеличивается как 1,2,3,4,n
    • pre if i =1 цикл увеличивается как 2,3,4,5,n
avatar
Anands23
13 мая 2016 в 05:50
10

++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. Но в зависимости от логики вашей программы он может отличаться.

avatar
srinath
14 ноября 2013 в 13:01
-6

Вот пример, чтобы понять разницу

int i=10;
printf("%d %d",i++,++i);

вывод: 10 12/11 11 (в зависимости от порядка вычисления аргументов функции printf, который зависит от компилятора и архитектуры)

Пояснение: i++-> i печатается, а затем увеличивается. (Отпечатает 10, но i станет 11) ++i-> i значение увеличивает и печатает значение. (Выводит 12, а значение i также 12)

M.M
21 октября 2014 в 01:19
11

Это вызывает неопределенное поведение, поскольку между i++ и ++i нет точки последовательности.

Antti Haapala
26 августа 2017 в 04:41
0

@Lundin - это правильно, хотя LHS, RHS запятой имеют точку последовательности между ними, но 2 выражения все еще не упорядочены друг относительно друга

avatar
Scitech
17 сентября 2013 в 12:23
9

++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
avatar
GokhanAvci
22 августа 2013 в 17:25
5

Коротко:

++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
Jonathan Leffler
4 марта 2015 в 22:53
3

На самом деле разница не связана с вызовами функций (и вы можете заметить разницу, не выполняя вызовов функций). Есть разница между int j = ++i; и int k = i++;, даже если не задействован вызов функции.

avatar
Shivprasad Koirala
25 июля 2013 в 07:42
43

i++: в этом сценарии сначала присваивается значение, а затем происходит приращение.

++i: в этом сценарии сначала выполняется приращение, а затем присваивается значение

Ниже представлена ​​визуализация изображения, а также , а вот хорошее практическое видео, которое демонстрирует то же самое.

enter image description here

kouty
19 января 2020 в 23:03
0

Как можно увеличить то, что не назначено?

Polluks
2 июня 2020 в 09:06
0

@kouty Вы можете увеличивать регистр, не назначенный переменной.

avatar
munna
22 января 2013 в 09:13
-3

a = i ++ означает, что a содержит текущее значение i a = ++ i означает, что a содержит увеличенное значение i

Jonathan Leffler
4 марта 2015 в 22:55
10

Это неточный ответ. a = i++; означает, что значение, хранящееся в a, будет значением i перед приращением, но «без приращения» означает, что i не увеличивается, что совершенно неверно - i увеличивается, но значение выражения - это значение до приращения.

avatar
Parag
28 марта 2012 в 05:54
208

i ++ известен как Пост-инкремент , тогда как ++ i называется <55338906> <55824833990> <55824833990> Приращение.

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 после увеличения i на i. Аналогично ++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.

Abdul Alim Shakir
4 февраля 2018 в 10:35
1

Инициализация переменных после префикса и пост-исправления помогает понять. Спасибо.

avatar
Scott Urban
4 августа 2011 в 17:20
5

Я полагаю, вы теперь понимаете разницу в семантике (хотя, честно говоря, мне интересно, почему люди спрашивают, что означает оператор X, вопросы о переполнении стека, а не о чтении, ну знаете, книгу или веб-руководство или что-то в этом роде.

Но в любом случае, что касается того, какой из них использовать, игнорируйте вопросы производительности, которые вряд ли важно даже в C ++. Это принцип, который вы должны использовать при принятии решения который использовать:

Скажите, что вы имеете в виду в коде.

Если вам не нужно значение до приращения в вашем операторе, не используйте эту форму оператора. Это незначительная проблема, но если вы не работаете с руководством по стилю, которое запрещает его версию в пользу другой (также известной как руководство по стилю), вы должны использовать форма, наиболее точно отражающая то, что вы пытаетесь сделать.

QED, используйте версию до инкремента:

for (int i = 0; i != X; ++i) ...
avatar
dusktreader
6 мая 2011 в 21:36
16

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

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

Однако следует рассмотреть две основные проблемы с предыдущей логикой.

  1. Современные компиляторы великолепны. Все хорошие компиляторы достаточно умны, чтобы понимать, что они видят целочисленное приращение в цикле for, и оптимизируют оба метода для получения одного и того же эффективного кода. Если использование постинкремента вместо преинкремента действительно приводит к тому, что ваша программа работает медленнее, тогда вы используете ужасный компилятор .

  2. С точки зрения сложности времени работы эти два метода (даже если копирование фактически выполняется) эквивалентны. Количество инструкций, выполняемых внутри цикла, должно значительно преобладать над количеством операций в операции приращения. Следовательно, в любом цикле значительного размера штраф метода приращения будет значительно перекрыт выполнением тела цикла. Другими словами, вам гораздо лучше беспокоиться об оптимизации кода в цикле, а не об инкременте.

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

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

avatar
Andy Lester
20 сентября 2008 в 05:06
48

Пожалуйста, не беспокойтесь о «эффективности» (на самом деле, скорости), какая из них выше. В наши дни у нас есть компиляторы, которые заботятся об этом. Используйте то, что имеет смысл использовать, исходя из того, что более четко демонстрирует ваши намерения.

underscore_d
29 сентября 2018 в 22:47
3

что, я надеюсь, означает « использовать префикс (inc | dec) rement, если вам действительно не нужно старое значение перед (inc | dec), что очень немногие люди делают, и тем не менее ошеломляющая доля предполагаемого обучения использование материалов, создание карго-культа пользователей постфикса, которые даже не знают, что это такое '..!

Peter - Reinstate Monica
7 мая 2019 в 10:09
2

Я не уверен, что «компиляторы в наши дни ... позаботятся об этих вещах» универсально верно. В пользовательском operator++(int) (версия с постфиксом) код в значительной степени должен создать временное, которое будет возвращено. Вы уверены, что компиляторы всегда могут это оптимизировать?

avatar
OysterD
24 августа 2008 в 06:00
25

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

Я стараюсь не слишком полагаться на оптимизацию компиляторов, поэтому я следую совету Райана Фокса: когда я могу использовать оба, я использую ++i.

R.. GitHub STOP HELPING ICE
6 октября 2010 в 08:17
13

-1 за ответ C ++ на вопрос C. "Локальной копии" значения i не больше, чем у значения 1, когда вы пишете оператор 1;.

avatar
Ryan Fox
24 августа 2008 в 05:21
46

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

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

Это небольшая разница.

Для цикла for используйте ++i, так как он немного быстрее. i++ создаст дополнительную копию, которую просто выбрасывают.

blabla999
12 января 2009 в 21:50
25

Я не знаю ни одного компилятора, в котором это имеет значение, по крайней мере, для целых чисел.

wildplasser
1 октября 2017 в 16:05
7

Это не быстрее . Значения игнорируются (действует только побочный эффект), и компилятор может / будет генерировать точно такой же код.