У 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, а також значення i
12)
i++
та++i