Założenia:
- Dana jest tablica liczb
arr[]typuinti liczbaidxwiększa od 0 i mniejsza niż wielkość tablicy pomniejszona o 1. - W tablicy są różne liczby, ale często jest kilka kolejnych elementów mających tą samą liczbę.
- Zadanie polega na znalezieniu numeru pierwszego elementu zawierającego tą sama liczbę, jaką zawiera element
idx.
Pytanie jest następujące: Czy poniższy sposób rozwiązania jest bezpieczny?
int numSerie = arr[idx];
while ((idx >= 0) && (arr[idx] == numSerie))
{
idx--;
}
idx++
Przykładowa niebezpieczna sytuacja:
int[] arr = { 7, 7, 7, 7, 5, 5, 5, 6, 6, 6};
int idx = 2;
Moim zdaniem, to, co zdarzy się po uruchomieniu powyższego kodu zależy od tego, jak kompilator zoptymalizuje linię z instrukcją while i możliwe są trzy przypadki (napiszę językiem ludzkim, tak, jakby to człowiek robił ręcznie):
- Komputer widzi, że jest "&&" i wie, ze muszą być spełnione oba warunki. Stwierdza, że pierwszy warunek nie jest spełniony (a nie będzie spełniony dla
idx = -1), więc nie ma po co sprawdzać drugiego warunku, bo i tak, niezależnie od tego, całe wyrażenie będzie fałszywe. - Program zadziała i po końcowej inkrementacji idx przyjmie 0. - Kompilator w ramach "optymalizacji" może odwrócić kolejność sprawdzania warunków, (&& jest przemienne, więc jaka to różnica, w jakiej kolejnosci są sprawdzane oba warunki). Program WYSYPIE SIĘ w powyższym przypadku, bo nastąpi próba odczytania elementu tablicy o indeksie -1!
- Komputer sprawdza cały warunek poprzez ustalanie elementów składowych od najbardziej zagnieżdżonego do całości, niezależnie od kolejności zapisania warunków w kodzie. Program WYSYPIE SIĘ w powyższym przypadku!
U mnie akurat działa (testy praktyczne na Linux i OpenJDK) i zachodzi pierwsza opcja, bo program nie wysypuje się, a wysypuje się po zamianie kolejności warunków w while, ale jaką mam gwarancję, że będzie działać na każdym JDK/JVM po skompilowaniu dowolnym kompilatorem Java?
Inny przykład obrazujący ten sam problem:
String str = "Jakis tam tekst";
idx = 20;
if ((str.length() > idx) && (str.charAt(idx) == ' '))
{
System.out.printLn("Trafiono na spację"):
}
Czy kod może wysypać się, gdy idx >= str.length()? Program zadziała poprawnie tylko w sytuacji, gdy stwierdzenie niespełnienia pierwszego warunku implikuje odstąpienie od sprawdzenia drugiego. Ale skąd mogę wiedzieć, co kompilaror faktycznie zrobi z tym kodem?