… czyli jak mała literówka może stać się źródłem poważnego problemu.
Na sam początek – mam procesor na architekturze x86 i gcc 4.1.2, nie ręczę za to, że na innych program przedstawiony poniżej będzie tak samo działać. U mnie i u mojego przyjaciela jednak właśnie tak było.
Przyjaciel mój odezwał się do mnie z problemami ze swoim programem sortującym. Po małym połataniu kodu, natrafiliśmy na nieskończoną pętlę, która w tym kodzie wystąpić nie miała prawa, a jednak w jakiś sposób wystąpiła. W feralnej pętli przy każdej iteracji zmienna iteratora miała stałą wartość, pomimo dekrementacji wykonywanej na niej za każdym razem. Co więc nadpisywało zmienną? Wyobraźmy sobie taki przykład:
#include <stdio.h>
int main() {
int arr[2];
int a, b, c, d, i;
for(i = 0; i < 6; i++)
arr[i] = i;
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}
Po skompilowaniu i uruchomieniu:
dragonee@hikari ~/dev 12:50:13 $ ./a.out 2 3 4 5 dragonee@hikari ~/dev 12:50:16 $
Wyjście poza tablicę nadpisuje następne zmienne. Nieprzyjemna sprawa, bo w ten sposób możemy przepisać te zmienne, które będą niezbędne do działania kodu. Albo trafimy dokłanie w taki punkt, który skończy się nieskończoną pętlą. Segmentation fault w tym przypadku wydaie się najprzyjemniejszym zakończeniem tego programu, bo od razu będziemy wiedzieć, że coś niedobrego z pamięcią się dzieje.
Niestety, my natrafiliśmy na nieskończoną pętlę. Zmienna iteracyjna była pierwszą po tablicy, a wartość, którą wpisywaliśmy do iteratora w tablicy wskazywała dokładnie na iterator. Dzięki temu mimo dekrementacji nic się nie zmieniało, a program działał i działał i działał…
Aby wszystko zadziałało, wystarczyło zwiększyć tylko rozmiar tablicy o 1 element. Na co trafiliśmy po godzinie wpatrywania się w 50 linii kodu.
Dlatego w przypadku tego typu iteracji lepiej w pętli operować bezpośrednio na rozmiarze tablicy lub zapisywać sobie wcześniej odpowiednią ilość pól w #define (i stosować tą stałą zarówno w deklaracji, i iteratorze).
Przy okazji wpadłem na ciekawy pomysł:
Ładna pętla nieskończona się robi. Trochę jak samomodyfikujący się kod 😉
deely
Pozwoliłem sobie zmodyfikować Twój komentarz, bo Textile źle zrozumiało nawiasy przy definicji tab. Przy okazji wstawiłem kod w blok. 😉
O, dzięki. Od razu lepiej 😉