INF.04 · pytanie 193
W zaprezentowanym fragmencie kodu występuje błąd logiczny. Na czym on polega? int x = 0; while (x != 0 || x != 5) { std::cout << x << " "; x++; }
- Anieprawidłowym warunku pętli, który sprawia, że pętla jest nieskończonaPoprawna
- Bbraku inicjalizacji zmiennej x, który sprawia, że zmienna nie ma wartości początkowej
- Cnieprawidłowym warunku pętli, który sprawia, że pętla nigdy się nie wykona
- Dbłędnym zastosowaniu funkcji cout, który sprawia, że zmienna jest wczytywana w pętli
Wyjaśnienie
Sedno problemu jest w warunku pętli: while (x != 0 || x != 5). Operator || oznacza alternatywę logiczną, czyli wystarczy, że jedna część warunku będzie prawdziwa. A tutaj dla każdej możliwej wartości x przynajmniej jeden z warunków zawsze będzie prawdziwy. Gdy x wynosi 0, wyrażenie x != 0 jest fałszywe, ale x != 5 jest prawdziwe, więc całość daje true. Gdy x wynosi 5, odwrotnie: x != 0 jest prawdziwe, a x != 5 fałszywe. Dla innych wartości oba warunki są prawdziwe. W efekcie pętla nie ma normalnego logicznego momentu zakończenia. Moim zdaniem to klasyczny przykład błędu, który dobrze pokazuje, że przy warunkach z != trzeba bardzo uważać na ||. W praktyce programistycznej taki błąd może zawiesić program, zablokować wątek, zużyć CPU albo doprowadzić do problemów w aplikacji serwerowej. Dobra praktyka to rozpisanie sobie tabeli prawdy albo sprawdzenie warunków brzegowych: x = 0, x = 5 i jakaś inna wartość. Jeśli celem było zatrzymanie przy 5, wystarczyłoby np. while (x != 5). Jeśli celem było wykonywanie pętli tylko wtedy, gdy x nie jest ani 0, ani 5, należałoby użyć &&: x != 0 && x != 5, choć przy początkowym x = 0 taka pętla nie ruszy. W C++ warto też pamiętać, że przy ciągłym zwiększaniu zmiennej int może dojść do przepełnienia typu ze znakiem, co według standardu C++ prowadzi do niezdefiniowanego zachowania, więc technicznie program jest jeszcze bardziej ryzykowny niż zwykła nieskończona pętla.