У C, в чому різниця між використанням ++iі i++і що слід використовувати в блоці forнарощення циклу?
У C, в чому різниця між використанням ++iі i++і що слід використовувати в блоці forнарощення циклу?
Відповіді:
++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; } мого розуміння, що деякі мови дадуть вам різні результати залежно від того, якими ви користуєтесь.
i++оскільки він має форму "операнд-оператор", а-ля - присвоєння "значення операнда-оператора-значення". Іншими словами, цільовий операнд знаходиться з лівого боку виразу, як і в операторі призначення.
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 називається " попереднім збільшенням".
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(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.
Будь ласка, не турбуйтеся про "ефективність" (швидкість, дійсно), яка з них швидша. У наші дні у нас є компілятори, які опікуються цими речами. Використовуйте те, що має сенс використовувати, виходячи з того, що більш чітко показує ваші наміри.
operator++(int)(postfix версії) коді в значній мірі необхідно створити тимчасовий, який буде повернутий. Ви впевнені, що компілятори завжди можуть оптимізувати це?
++i збільшує значення, а потім повертає його.
i++ повертає значення, а потім збільшує його.
Це тонка різниця.
Для циклу for, використовуйте ++i, оскільки це трохи швидше. i++створить додаткову копію, яка просто викидається.
i++: У цьому сценарії спочатку присвоюється значення, а потім відбувається приріст.
++i: У цьому сценарії спочатку робиться приріст, а потім присвоюється значення
Нижче представлена візуалізація зображення, а також ось приємне практичне відео, яке демонструє те саме.

Причина ++i може бути трохи швидшою, ніж i++те, що i++може вимагати локальної копії значення i до того, як воно збільшується, тоді як ++iніколи. У деяких випадках деякі компілятори оптимізують її за можливістю ... але це не завжди можливо, і не всі компілятори роблять це.
Я намагаюся не надто покладатися на оптимізацію компіляторів, тому дотримуюся порад Райана Фокса: коли я можу використовувати обоє, я використовую ++i.
iКоли ви пишете заяву, немає "локальної копії" значення, ніж значення 1 1;.
Ефективний результат використання будь-якого циклу однаковий. Іншими словами, цикл буде робити те саме, що і в обох випадках.
З точки зору ефективності, може бути застосовано покарання за вибір i ++ над ++ i. З точки зору мовної специфікації, використовуючи оператор після збільшення, слід створити додаткову копію значення, на яке діє оператор. Це може стати джерелом додаткових операцій.
Однак слід розглянути дві основні проблеми з попередньою логікою.
Сучасні компілятори чудові. Всі хороші компілятори досить розумні, щоб зрозуміти, що він бачить ціле збільшення у for-циклі, і це оптимізує обидва методи до одного ефективного коду. Якщо використання посткраста над попереднім збільшенням насправді призводить до того, що у вашої програми буде повільніше час роботи, ви використовуєте жахливий компілятор.
Що стосується трудомісткості часу, два методи (навіть якщо копія реально виконується) є рівнозначними. Кількість вказівок, що виконуються всередині циклу, повинна значно переважати над кількістю операцій із збільшенням операції. Тому в будь-якому циклі значного розміру покарання методу приросту буде масово затьмарено виконанням тіла циклу. Іншими словами, вам набагато краще перейматися оптимізацією коду в циклі, а не збільшенням.
На мою думку, все питання просто зводиться до стильових уподобань. Якщо ви вважаєте, що попередній приріст є більш читабельним, тоді використовуйте його. Особисто я віддаю перевагу пост-інкрументації, але це, мабуть, тому, що це було те, чого мене навчали, перш ніж я щось знав про оптимізацію.
Це найважливіший приклад передчасної оптимізації, і такі проблеми можуть відволікти нас від серйозних проблем дизайну. Однак все-таки добре поставити питання, оскільки немає «однакової форми використання або консенсусу в« найкращій практиці ».
Вони обидва збільшують число. ++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
++i(Операція префікс): збільшення , а потім привласнює значення
(наприклад): int i = 5, int b = ++i
в цьому випадку, 6 призначаються б, а потім збільшення до 7 і так далі.
i++(Операція Постфікс): Призначає , а потім збільшує значення
(наприклад): int i = 5, int b = i++
в цьому випадку 5 призначаються б, а потім збільшення до 6 і так далі.
Incase of for циклу: i++використовується в основному тому, що, як правило, ми використовуємо вихідне значення iдо збільшення для циклу. Але залежно від логіки вашої програми вона може змінюватися.
Я припускаю, що ви зараз розумієте різницю в семантиці (хоча, чесно кажучи, мені цікаво, чому люди задають питання "що означає оператор X" на питаннях переповнення стека, а не читання, знаєте, книги чи веб-підручника чи чогось іншого.
Але як би там не було, ігнорувати продуктивність, які навряд чи важливі навіть у C ++. Це принцип, який ви повинні використовувати, вирішуючи, який використовувати:
Скажіть, що ви маєте на увазі під кодом.
Якщо у вашому виписці вам не потрібна цінність перед збільшенням, не використовуйте цю форму оператора. Це незначна проблема, але якщо ви не працюєте з посібником зі стилів, який взагалі забороняє одну версію на користь іншої (він називається керівництвом по стилю з кісткою), ви повинні використовувати форму, яка найбільш точно виражає те, що ви намагаєтеся зробити.
QED, використовуйте попередню приріст версії:
for (int i = 0; i != X; ++i) ...
Різницю можна зрозуміти за допомогою цього простого коду 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;
Основна різниця є
- Повідомлення i ++ ( після збільшення ) та
++ i Pre ( до збільшення )
i =1додати, якщо збільшується цикл, як1,2,3,4,n- попередньо, якщо
i =1наріст циклу подобається2,3,4,5,n
Цей невеликий код може допомогти візуалізувати різницю з іншого кута, ніж уже опубліковані відповіді:
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.
Наступний фрагмент коду С ілюструє різницю між операторами до збільшення та після збільшення та зменшення:
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
Попереднє створення означає приріст на одній лінії. Посткремент означає приріст після виконання рядка.
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
Якщо мова йде про операторів АБО І І, це стає цікавішим.
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)
}
Незабаром:
++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++;навіть тоді, коли немає функціонального дзвінка.
Єдина відмінність - це порядок операцій між збільшенням змінної і значенням, яке повертає оператор.
Цей код та його вихід пояснює різницю:
#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(int i=0; i<10; i++)
має той же ефект, що і
for(int i=0; i<10; ++i)
Щоб не робити плутанини між двома операторами, я прийняв це правило:
Пов’яжіть позицію оператора ++щодо змінної iдо порядку ++операції щодо призначення
Іншими словами:
++ перед тим, як i нарощування засобів має бути здійснено перед призначенням;++ після i того, як кошти інкрементація повинна виконуватися після завдання:Ви можете думати про внутрішню конверсію цього як про кілька заяв ;
i++;
ви можете подумати про це,
i;
i = i+1;
++i;
ви можете подумати про це,
i = i+i;
i;
a = i ++ означає, що містить поточне значення i a = ++ i означає, що містить збільшене значення i
a = i++;означає, що значення, збережене в, aбуде значенням iдо приросту, але "без збільшення" означає, що iвоно не збільшується, що абсолютно неправильно - iзбільшується, але значення виразу - це значення до збільшення.
Ось приклад, щоб зрозуміти різницю
int i=10;
printf("%d %d",i++,++i);
вихід: 10 12/11 11(залежно від порядку оцінки аргументів printfфункції, яка залежить від компіляторів та архітектур)
Пояснення:
i++-> iдрукується, а потім збільшується. (Друкує 10, але iстане 11)
++i-> iприріст значення та друкує значення. (Друкує 12, а також значення i12)
i++та++i