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

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

24.08.2008 05:19:19
Не уверен, что оригинальный постер заинтересован, но в C ++ разница в производительности может быть существенной, поскольку создание временного объекта может быть дорогим для определенного пользователем типа.
On Freund 24.08.2008 05:57:30
RiaD 9.01.2016 22:21:12
@RiaD Этот старше.
L. F. 4.05.2019 05:46:57
21 ОТВЕТ
РЕШЕНИЕ
  • ++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++()это функция, и компилятор не может знать, как оптимизировать создание временного объекта для хранения промежуточного значения.

1072
28.02.2020 10:40:26
Разве этот эффект не выдержит повторение цикла после достижения конечного состояния? Например, for(int i=0; i<10; i++){ print i; } не будет ли это отличаться от for(int i=0; i<10; ++i){ print i; } моего понимания в том, что некоторые языки будут давать разные результаты в зависимости от того, что вы используете.
aVeRTRAC 16.08.2011 17:58:57
jonnyflash, оба будут работать одинаково, поскольку приращение i и print находятся в разных операторах. Это должно иметь место для любого языка, который поддерживает C-стиль ++. Единственное различие между ++ i и i ++ будет при использовании значения операции в одном выражении.
Mark Harrison 16.08.2011 18:44:26
Поскольку в большинстве случаев они генерируют идентичный код, я предпочитаю, i++потому что он имеет форму «операнд-оператор», а именно присваивание «операнд-оператор-значение». Другими словами, целевой операнд находится в левой части выражения, как и в операторе присваивания.
David R Tribble 11.12.2012 16:49:42
@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 в первом комментарии.
Adam 17.04.2014 08:55:09
@sam, потому что в типичном цикле for нет побочного эффекта (например, присваивания) в части ++ i.
Mark Harrison 24.03.2015 04:57:58

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

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

Это тонкая разница.

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

33
26.06.2015 10:40:58
Я не знаю ни о каком компиляторе, где он имеет значение по крайней мере для целых чисел.
blabla999 12.01.2009 21:50:13
Это не быстрее . Значения игнорируются (эффективен только побочный эффект), и компилятор может / будет генерировать точно такой же код.
wildplasser 1.10.2017 16:05:09

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

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

20
26.06.2015 10:41:58
-1 для C ++ ответ на C вопрос. Нет более локальной копии значения, iчем значение 1, когда вы пишете оператор 1;.
R.. GitHub STOP HELPING ICE 6.10.2010 08:17:44

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

41
26.02.2014 21:57:50
что, я надеюсь, означает « использовать префикс (inc | dec) rement, если только вам на самом деле не нужно старое значение до (inc | dec)», как это делают очень немногие, и, тем не менее, изумительная доля предполагаемых учебных материалов, используемых, создание культового груза пользователей постфикса, которые даже не знают, что это такое
underscore_d 29.09.2018 22:47:32
Я не уверен, что "компиляторы в наши дни ... заботятся об этих вещах" универсально верно. В обычае operator++(int)(постфиксная версия) код должен создать временный объект, который будет возвращен. Вы уверены, что компиляторы всегда могут оптимизировать это?
Peter - Reinstate Monica 7.05.2019 10:09:58

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

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

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

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

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

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

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

14
21.03.2020 17:33:36

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

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

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

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

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

for (int i = 0; i != X; ++i) ...
5
4.08.2011 17:20:53

i ++ известен как Post Increment, тогда как ++ 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после 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.

171
27.09.2017 13:55:54
Инициализация переменных после префикса и после исправления помогает понять. Спасибо.
Abdul Alim Shakir 4.02.2018 10:35:30

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

-3
17.03.2018 09:56:02
Этот ответ не точен. a = i++;означает, что значение, хранимое в, aбудет значением iдо приращения, но «без приращения» подразумевает, что iне увеличивается, что совершенно неправильно - iувеличивается, но значение выражения является значением до приращения.
Jonathan Leffler 4.03.2015 22:55:51

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

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

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

введите описание изображения здесь

31
8.06.2019 07:11:22
Как вы можете увеличить немного не назначен?
kouty 19.01.2020 23:03:14

Коротко:

++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
4
8.06.2019 07:10:26
Разница на самом деле не связана с вызовами функций (и вы можете заметить разницу, не делая вызовов функций). Есть разница между int j = ++i;и int k = i++;даже тогда, когда нет вызова функции.
Jonathan Leffler 4.03.2015 22:53:52

++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
7
8.06.2019 07:09:30

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

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

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

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

-6
9.01.2017 16:29:52
Это приводит к неопределенному поведению , так как не имеет смысла последовательности между i++и++i
M.M 21.10.2014 01:19:09
@Lundin это правильно, хотя, LHS, RHS запятой имеют точку последовательности между ними, но эти два выражения по-прежнему не последовательны друг с другом
Antti Haapala 26.08.2017 04:41:36

++i(Операция Префикса): приращения , а затем присваивает значение
(например): int i = 5, int b = ++i в этом случае, 6 назначаются б, а затем приращения до 7 и так далее.

i++(Операция Постфикса): Назначает , а затем увеличивает значение
(например): int i = 5, int b = i++ в этом случае 5 назначаются б, а затем приращения до 6 и так далее.

Incase для цикла for: i++в основном используется потому, что обычно мы используем начальное значение iперед увеличением цикла for. Но в зависимости от логики вашей программы это может варьироваться.

8
8.06.2019 07:08:53

Главное отличие

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

    • опубликовать, если i =1 цикл увеличивается как1,2,3,4,n
    • предварительно, если i =1 цикл увеличивается как2,3,4,5,n
5
17.03.2018 06:40:31

Разницу можно понять по следующему простому коду 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;
5
12.09.2017 21:13:13

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

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)
}
4
8.06.2019 07:07:10

Следующий фрагмент кода 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
5
8.06.2019 07:06:09

Они оба увеличивают число. ++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
13
8.06.2019 07:05:32

я ++ и ++ я

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

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.

5
8.06.2019 07:04:35

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

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

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

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

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

i = i+i;
i;
2
3.01.2020 15:44:01

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

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

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  a = i++;
  printf("i before: %d; value returned by i++: %d, i after: %d\n", i, a, i);
  i=0;
  a = ++i;
  printf("i before: %d; value returned by ++i: %d, i after: %d\n", i, a, i);
}

Выход:

i before: 1; value returned by i++: 0, i after: 1
i before: 1; 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с порядком ++операции относительно назначения

Сказал другими словами:

  • ++ before i Приращение средств должно быть выполнено перед присваиванием;
  • ++ после i приращения средств должно быть выполнено после назначения:
2
7.03.2019 09:51:44