Post-increment i pre-increment w pętli ' for ' dają to samo wyjście [duplikat]

to pytanie ma już odpowiedzi tutaj : różnica między Pre-inkrementacją a post-inkrementacją w pętli? (22 odpowiedzi) Zamknięty 6 lat temu .

Następujące pętle for dają identyczne wyniki, mimo że jedna używa post increment, a druga pre-increment.

Oto kod:

for(i=0; i<5; i++) {
    printf("%d", i);
}

for(i=0; i<5; ++i) {
    printf("%d", i);
}

Otrzymuję to samo wyjście dla obu pętli 'for'. Coś przeoczyłem?

Author: nabster, 2011-01-16

12 answers

Po dokonaniu oceny i++ LUB ++i, nowa wartość i będzie taka sama w obu przypadkach. Różnica między pre-i post-incrementem jest wynikiem oceny samego wyrażenia.

++i przyrosty i i ewaluuje do nowej wartości i.

i++ wartościuje do starej wartości i i przyrosty i.

Powodem, dla którego nie ma to znaczenia w pętli for, Jest to, że przepływ sterowania działa mniej więcej tak:

  1. przetestuj warunek
  2. jeśli jest false, Zakończ
  3. jeśli to prawda, wykonaj ciało
  4. wykonaj krok inkrementacji

Ponieważ (1) i (4) są odsprzęgnięte, można użyć pre - lub post-increment.

 345
Author: danben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-28 18:34:45

To proste. Powyższe pętle for są semantycznie równoważne

int i = 0;
while(i < 5) {
    printf("%d", i);
    i++;
}

I

int i = 0;
while(i < 5) {
    printf("%d", i);
    ++i;
}

Zauważ, że linie i++; i ++i; mają tę samą semantykę z perspektywy tego bloku kodu. Obie mają taki sam wpływ na wartość i (zwiększają ją o jeden) i dlatego mają taki sam wpływ na zachowanie tych pętli.

Zauważ, że byłaby różnica, gdyby pętla została przepisana jako

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = ++i;
}

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = i++;
}

To dlatego, że w pierwszym blok kodu j widzi wartość i po inkrementacji (i jest inkrementowany pierwszy lub wstępnie inkrementowany, stąd nazwa), a w drugim bloku kodu j widzi wartość i przed inkrementacją.

 119
Author: jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 15:38:38

Wynik twojego kodu będzie taki sam. Powodem jest to, że dwie operacje inkrementacji mogą być postrzegane jako dwa różne wywołania funkcji. Obie funkcje powodują przyrost zmiennej i tylko ich wartości zwracane są różne. W tym przypadku wartość zwracana jest po prostu odrzucana, co oznacza, że nie ma rozróżnialnej różnicy na wyjściu.

Jednak pod maską jest różnica: post-inkrementacja i++ musi stworzyć tymczasowy zmienna aby zapisać oryginalną wartość i, następnie wykonuje inkrementację i zwraca zmienną tymczasową. Pre-inkrementacja ++i nie tworzy zmiennej tymczasowej. Oczywiście, każde przyzwoite ustawienie optymalizacji powinno być w stanie to zoptymalizować, gdy obiekt jest czymś prostym, jak int, ale pamiętaj, że operatory ++są przeciążone w bardziej skomplikowanych klasach, takich jak Iteratory. Ponieważ dwie przeciążone metody mogą mieć różne operacje (jedna może chcieć wypisać "Hej, jestem pre-incremented!"na przykład stdout) kompilator nie może stwierdzić, czy metody są równoważne, gdy wartość zwracana nie jest używana (w zasadzie dlatego, że taki kompilator rozwiązałby nierozwiązywalny problem wstrzymania), musi użyć droższej wersji post-incrementacyjnej, jeśli napiszesz myiterator++.

Trzy powody, dla których należy pre-increment:

  1. nie będziesz musiał zastanawiać się, czy zmienna / obiekt może mieć przeciążoną post-inkrementację metody (np. w funkcji szablonu) i traktować ją inaczej (lub zapomnieć traktować inaczej).
  2. spójny kod wygląda lepiej.
  3. kiedy ktoś pyta " dlaczego pre-inkrementacji?"będziesz miał okazję nauczyć ich o problemie zatrzymania i teoretycznych granicach optymalizacji kompilatora . :)
 96
Author: Anders Sjöqvist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-09 03:27:15

To jedno z moich ulubionych pytań w wywiadzie. Najpierw wyjaśnię odpowiedź, a potem powiem, DLACZEGO podoba mi się to pytanie.

Rozwiązanie:

Odpowiedź jest taka, że oba fragmenty drukują liczby od 0 do 4, włącznie. Jest to spowodowane tym, że pętla for() jest ogólnie równoważna pętli while():

for (INITIALIZER; CONDITION; OPERATION) {
    do_stuff();
}

Można zapisać:

INITIALIZER;
while(CONDITION) {
    do_stuff();
    OPERATION;
}

Możesz zobaczyć, że operacja jest zawsze wykonywana na dole pętli. W tej formie powinno być Wyczyść, że i++ i ++i będą miały ten sam efekt: zarówno zwiększą i, jak i zignorują wynik. Nowa wartość i nie jest testowana, dopóki nie rozpocznie się kolejna iteracja, u góry pętli.


Edit : podziękowania dla Jasona za zwrócenie uwagi, że ta for() do while() równoważność Nie utrzymuje się, jeśli pętla zawiera instrukcje kontrolne (takie jak continue), które uniemożliwiałyby OPERATION wykonanie w pętli while(). OPERATION jest zawsze wykonywane tylko przed kolejną iteracją pętli for().


Dlaczego to dobre pytanie o wywiad

Po pierwsze, to trwa tylko minutę lub dwie, jeśli kandydat natychmiast powie poprawną odpowiedź, więc możemy przejść od razu do następnego pytania.

Ale zaskakująco (dla mnie), wielu kandydatów mówi mi, że pętla z przyrostem post wydrukuje liczby od 0 do 4, a pętla przed przyrostem wydrukuje od 0 do 5 lub od 1 do 5. Zwykle wyjaśniają różnicę pomiędzy pre - i post-inkrementacją poprawnie, ale nie rozumieją mechaniki pętli for().

W takim przypadku proszę ich o przepisanie pętli za pomocą while(), a to naprawdę daje mi dobre wyobrażenie o ich procesach myślowych. I dlatego w pierwszej kolejności zadaję pytanie: Chcę wiedzieć, jak podchodzą do problemu i jak postępują, gdy kwestionuję sposób, w jaki działa ich świat.

W tym momencie większość kandydatów uświadamia sobie swój błąd i znajduje poprawną odpowiedź. Ale miałem jednego, który upierał się, że jego oryginalna odpowiedź jest prawidłowa, a następnie zmienił sposób, w jaki przetłumaczył for() na while(). To był fascynujący wywiad, ale nie złożyliśmy oferty!

Mam nadzieję, że to pomoże!
 31
Author: Adam Liss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 16:03:14

Ponieważ w obu przypadkach przyrost jest wykonywany po ciele pętli i tym samym nie wpływa na żadne obliczenia pętli. Jeśli kompilator jest głupi, może być nieco mniej wydajne użycie post-increment (ponieważ normalnie musi zachować kopię wartości pre do późniejszego użycia), ale spodziewałbym się, że wszelkie różnice zostaną zoptymalizowane w tym przypadku.

Przydałoby się pomyśleć o tym, jak pętla for jest zaimplementowana, zasadniczo przetłumaczona na zbiór zadania, testy i instrukcje oddziału. W pseudo-kodzie pre-increment wyglądałby następująco:

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set i = i + 1
      goto test
done: nop

Post-increment miałby co najmniej kolejny krok, ale optymalizacja byłaby trywialna

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set j = i   // store value of i for later increment
      set i = j + 1  // oops, we're incrementing right-away
      goto test
done: nop
 8
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 15:45:18

Gdybyś tak to napisał to by miało znaczenie:

for(i=0; i<5; i=j++) {
    printf("%d",i);
}

Powtórzyłoby się jeszcze raz, gdyby było napisane tak:

for(i=0; i<5; i=++j) {
    printf("%d",i);
}
 5
Author: iss42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-20 02:50:15

Możesz przeczytać Google answer dla niego tutaj: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preincrement_and_Predecrement

Więc, najważniejsze jest to, że nie ma różnicy dla simple object, ale dla iteratorów i innych obiektów szablonowych powinieneś użyć preincrement.

Edycja:

Nie ma różnicy, ponieważ używasz prostego typu, więc nie ma efektów ubocznych, a post - lub preincrements wykonywane po ciele pętli, więc nie ma wpływu na wartość w pętli ciało.

Można to sprawdzić za pomocą takiej pętli:

for (int i = 0; i < 5; cout << "we still not incremented here: " << i << endl, i++)
{
    cout << "inside loop body: " << i << endl;
}
 3
Author: Yola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 19:20:35

Zarówno i++, jak i ++i są wykonywane po wykonaniu printf ("%d", i) za każdym razem, więc nie ma żadnej różnicy.

 2
Author: Hoàng Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 15:38:24

Tak, otrzymasz dokładnie takie same wyniki dla obu. dlaczego uważasz, że powinny dać ci różne wyniki?

Post-inkrement lub pre-inkrement ma znaczenie w takich sytuacjach:

int j = ++i;
int k = i++;
f(i++);
g(++i);

Gdzie podajesz jakąś wartość, przypisując lub przekazując argument. Nie robisz nic w swoich for pętlach. Tylko się zwiększa. Post - i pre-nie ma sensu!

 1
Author: Nawaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 15:42:08

Trzecia instrukcja w konstrukcji for jest tylko wykonywana, ale jej wartość jest odrzucana i nie jest brana pod uwagę.
Gdy obliczona wartość jest odrzucana, pre i post increment są równe.
Różnią się tylko wtedy, gdy ich wartość jest brana.

 1
Author: Petruza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 05:38:46

Istnieje różnica, jeśli:

int main()
{
  for(int i(0); i<2; printf("i = post increment in loop %d\n", i++))
  {
    cout << "inside post incement = " << i << endl;
  }


  for(int i(0); i<2; printf("i = pre increment in loop %d\n",++i))
  {
    cout << "inside pre incement = " << i << endl;
  }

  return 0;
}

Wynik:

Inside Post incement = 0

I = post increment in loop 0

Inside Post incement = 1

I = post increment in loop 1

Drugi dla pętli:

Inside pre = 0

I = pre inkrement w pętli 1

Inside pre = 1

I = pre inkrement w pętli 2

 -1
Author: finding83,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-20 16:48:19

Kompilatory tłumaczą

for (a; b; c)
{
    ...
}

Do

a;
while(b)
{
    ...
 end:
    c;
}

Więc w Twoim przypadku (post/pre-increment) to nie ma znaczenia.

EDIT: kontynuacje są po prostu zastąpione przez goto end;

 -2
Author: jdehaan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 16:16:11