Egzamin zawodowyPortal części pisemnej

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++; }

  1. Anieprawidłowym warunku pętli, który sprawia, że pętla jest nieskończonaPoprawna
  2. Bbraku inicjalizacji zmiennej x, który sprawia, że zmienna nie ma wartości początkowej
  3. Cnieprawidłowym warunku pętli, który sprawia, że pętla nigdy się nie wykona
  4. 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.