[Dla przypomnienia, edytowałem tę odpowiedź dość znacząco, odkąd została zaakceptowana i poddana pod głosowanie. Jednak nadal mówi w zasadzie te same rzeczy.]
Ten kod jest głęboko, być może celowo, zagmatwany. Zawiera wąsko unikniętą instancję przerażającego niezdefiniowanego zachowania . Zasadniczo nie można ustalić, czy osoba, która skonstruowała to pytanie, była bardzo, bardzo sprytna, czy bardzo, bardzo głupia. A „lekcja”, jaką ten kod może uczyć lub wypytywać o ciebie - a mianowicie, że operator jednoargumentowy plus niewiele robi - z pewnością nie jest wystarczająco ważna, aby zasłużyć na tego rodzaju wywrotowe złe kierowanie.
Istnieją dwa mylące aspekty kodu, dziwny warunek:
while(+(+k--)!=0)
oraz oświadczenie, które kontroluje:
k=k++;
Najpierw omówię drugą część.
Jeśli masz taką zmienną k, którą chcesz zwiększyć o 1, C daje ci nie jeden, nie dwa, nie trzy, ale cztery różne sposoby:
k = k + 1
k += 1
++k
k++
Mimo tej nagrody (a może właśnie z tego powodu) niektórzy programiści są zdezorientowani i wykrztuszają skręty
k = k++;
Jeśli nie możesz zrozumieć, co to ma zrobić, nie martw się: nikt nie może. To wyrażenie zawiera dwie różne próby zmiany kwartości ( k =część i k++część), a ponieważ w C nie ma reguły określającej, która z prób modyfikacji „wygrywa”, wyrażenie takie jest formalnie niezdefiniowane , co oznacza nie tylko, że to nie zdefiniowane znaczenie, ale że cały program zawierający jest podejrzany.
Teraz, jeśli spojrzysz bardzo uważnie, zobaczysz, że w tym konkretnym programie linia k = k++nie jest tak naprawdę wykonywana, ponieważ (jak zobaczymy) warunek kontrolny jest początkowo fałszywy, więc pętla działa 0 razy . Więc ten konkretny program nie może faktycznie być zdefiniowana - ale to wciąż patologicznie mylące.
Zobacz także te kanoniczne SO odpowiedzi na wszystkie pytania dotyczące tego rodzaju niezdefiniowanego zachowania.
Ale nie pytałeś o tę k=k++część. Zapytałeś o pierwszą mylącą część, +(+k--)!=0warunek. To wygląda dziwnie, ponieważ jest dziwne. Nikt nigdy nie napisałby takiego kodu w prawdziwym programie. Nie ma więc powodu, aby nauczyć się go rozumieć. (Tak, to prawda, odkrywanie granic systemu może pomóc ci dowiedzieć się o jego drobnych punktach, ale w mojej książce jest dość wyraźna granica między pomysłowymi, prowokującymi do eksploracji eksploracjami a bzdurnymi, obraźliwymi eksploracjami, a to wyrażenie jest bardzo wyraźnie widoczne zła strona tej linii).
W każdym razie przyjrzyjmy się +(+k--)!=0. (A po zrobieniu tego, zapomnijmy o tym.) Każde takie wyrażenie musi być rozumiane od wewnątrz. Zakładam, że wiesz co
k--
robi. Pobiera kbieżącą wartość i „zwraca” ją do reszty wyrażenia i mniej więcej jednocześnie zmniejsza k, tzn. Zapisuje k-1ponownie wartość k.
Ale co to +robi? Jest to jednoskładnikowa, Plus, Plus nie binarny. To jest jak jednoargumentowy minus. Wiesz, że binarny minus robi odejmowanie: wyrażenie
a - b
odejmuje b od a. I wiesz, że jednoargumentowy minus neguje rzeczy: wyrażenie
-a
daje ci minus od. To, co +robi jedno , jest ... w zasadzie niczym. +adaje awartość po zmianie dodatnich wartości na dodatnie i ujemnych na ujemne. Więc wyrażenie
+k--
daje ci wszystko, co ci k--dało, czyli kstarą wartość.
Ale nie skończyliśmy, bo mamy
+(+k--)
To po prostu bierze wszystko, co +k--ci dano, i +znów odnosi się do tego jedno raz. Więc daje ci to, co ci +k--dało, co było k--ci, co dawało, co było kdawną wartością.
Tak więc w końcu warunek
while(+(+k--)!=0)
robi dokładnie to samo, co znacznie bardziej zwyczajny warunek
while(k-- != 0)
zrobiłby. (Robi to samo, co while(+(+(+(+k--)))!=0)zrobiłby to nawet bardziej skomplikowany wygląd . I te nawiasy nie są tak naprawdę konieczne; robi to samo, co while(+ + + +k--!=0)by zrobił).
Nawet zastanawianie się, jaki jest „normalny” stan
while(k-- != 0)
jest dość trudne. W tej pętli dzieją się dwie rzeczy: Ponieważ pętla działa potencjalnie wiele razy, zamierzamy:
k--rób dalej , aby robić kcoraz mniejsze, ale także
- dalej wykonuj ciało pętli, cokolwiek to zrobi.
Ale wykonujemy tę k--część od razu, zanim (lub w trakcie) decydujemy, czy podjąć kolejną podróż przez pętlę. I pamiętaj, że k--„zwraca” starą wartość kprzed jej zmniejszeniem. W tym programie początkowa wartość kwynosi 0. Więc k--„zwróci” starą wartość 0, a następnie zaktualizuje kdo -1. Ale reszta warunku jest != 0- ale jak właśnie widzieliśmy, przy pierwszym testowaniu warunku otrzymaliśmy 0. Więc nie będziemy robić żadnych pętli przez pętlę, więc nie będziemy próbować wykonać problematyczne stwierdzenie k=k++w ogóle.
Innymi słowy, w tej konkretnej pętli, chociaż powiedziałem, że „dzieje się coś w rodzaju dwóch rzeczy”, okazuje się, że rzecz 1 dzieje się raz, ale rzecz 2 dzieje się zero razy.
W każdym razie mam nadzieję, że teraz jest wystarczająco jasne, dlaczego ta marna wymówka dla programu kończy się na wydrukowaniu -1 jako wartości końcowej k. Zwykle nie lubię odpowiadać na pytania w quizie - czuję się jak oszukiwanie - ale w tym przypadku, ponieważ tak głośno nie zgadzam się z całym celem ćwiczenia, nie mam nic przeciwko.