Przecież w pętli mam warunek while( t[i] == 0 && i < n)
, zatem jeżeli tablica ma same zera, to i == n
, wtedy pętla zakończy działanie
Pętla zakończy działanie, ale najpierw sprawdzi, co znajduje się w tablicy
\(\displaystyle{ t}\) pod indeksem
\(\displaystyle{ n}\).
wydaje mi się, że poprawniej byłoby napisać while(i<n && t[i] == 0)
, choć i tak czy siak będzie fałsz
Tak, to by było poprawnym rozwiązaniem (zaznaczę, że
while( t[i] == 0 && i < n)
jest absolutnie niepoprawne)
Żeby zrozumieć czemu 2 opcja jest dobra, a pierwsza nie, musisz wiedzieć, że w C jest coś takiego jak "lazy evaluation" i kolejność obliczania wyrażeń.
W momencie, gdy i staje się równe n, program przejdzie do sprawdzenia warunku pętli. Warunek pętli składa się z koniunkcji dwóch wyrażeń logicznych i te wyrażenia będą ewaluowane od lewej do prawej.
Czyli i staje się n. Program zaczyna sprawdzać warunek pętli. Pierwszym warunkiem w koniunkcji jest
wobec tego program sięga do n + 1 elementu tablicy, by sprawdzić, czy tam jest zero, ale ten element nie istnieje, w tym miejsciu pamięci znajduje się coś kompletnie innego!
Teraz czemu "lazy evaluation" pozwala nam ominąć ten problem w drugim przypadku. Zauważ, że jedyne co się zmieniło w warunku pętli, to kolejność składników koniunkcji.
Więc znowu...
Załóżmy, że i staje się n. Program przechodzi do poczatku pętli i zaczyna sprawdzać jej warunek.
Ewaluuje składniki od lewej do prawej. Pierwszym składnikiem jest i < n.
No więc ewaluujemy go i widzimy, że on jest fałszywy. Ale warunek pętli jest koniunkcją (!), czyli już na tym etapie wiemy, że warunek pętli jest niespełniony, dlatego nasz leniwy program (stąd "lazy evaluation") w ogóle nie sprawdzi, czy
, bo do niczego mu to nie jest potrzebne, więc w tym wypadku jesteśmy bezpieczni i nie dojdzie do sięgniecia do pamięci, do której nie powinniśmy sięgać