lekcja programowania. najlepsze praktyki - pdf.helion.plpdf.helion.pl/prapro/prapro.pdf · jeli...

38

Upload: haque

Post on 01-Mar-2019

230 views

Category:

Documents


0 download

TRANSCRIPT

Idź do

• Spis treści• Przykładowy rozdział• Skorowidz

• Katalog online

• Dodaj do koszyka

• Zamów cennik

• Zamów informacjeo nowościach

• Fragmenty książekonline

Helion SAul. Kościuszki 1c44-100 Gliwicetel. 32 230 98 63e-mail: [email protected]© Helion 1991–2011

Katalog książek

Twój koszyk

Cennik i informacje

Czytelnia

Kontakt

• Zamów drukowanykatalog

Lekcja programowania.Najlepsze praktyki

Autorzy: Brian W. Kernighan, Rob Pike

Tłumaczenie: Łukasz Piwko

ISBN: 978-83-246-3226-8

Tytuł oryginału: The Practice of Programming

Format: 172×245, stron: 272

Twórz zgodnie z trzema zasadami stanowiącymi kanon dobrego oprogramowania

• Prostota – czyli kod prosty i łatwy w obsłudze

• Ogólność – czyli kod działający dobrze w różnych sytuacjach i adaptujący się do nowych

warunków

• Przejrzystość – czyli kod łatwy do zrozumienia zarówno przez ludzi, jak i maszyny

Czy zdarzyło Ci się kiedykolwiek…

• pominąć oczywisty błąd w programie i spędzić cały dzień na szukaniu go?

• próbować wprowadzić sensowne zmiany w programie napisanym przez kogoś innego?

• przepisać program od nowa, bo nie dało się go zrozumieć?

Jeśli tak, w przyszłości na pewno chciałbyś tego uniknąć! Takie problemy dla zbyt wielu

programistów są niestety chlebem powszednim. Dzieje się tak między innymi dlatego, że

testowanie, diagnostyka, przenośność, wydajność czy styl programowania są często traktowane

po macoszemu przez osoby tworzące oprogramowanie. A świat rządzony przez olbrzymie

interfejsy, wciąż zmieniające się narzędzia, języki czy systemy nie sprzyja podstawowym zasadom

tworzenia dobrego kodu – prostocie, ogólności i przejrzystości.

Programowanie to coś więcej niż samo pisanie kodu. W książce „Praktyka programowania”

znajdziesz opis wszystkich zagadnień, z którymi styka się programista – od projektowania,

poprzez usuwanie usterek, testowanie kodu czy poprawę jego wydajności, po problemy związane

z poprawianiem oprogramowania napisanego przez innych. Wszystko zostało oparte na

zaczerpniętych z realnych projektów przykładach, napisanych w językach C, C++, Java i innych.

Tylko tutaj znajdziesz omówienia następujących zagadnień:

• Styl: pisanie kodu, który dobrze działa i przyjemnie się czyta

• Projektowanie: wybór algorytmów i struktur danych najlepiej nadających się

do określonego zadania

• Interfejsy: kontrolowanie relacji między składnikami programów

• Usuwanie błędów: szybkie i metodyczne wyszukiwanie błędów

• Testowanie: zapewnianie niezawodności i poprawności oprogramowania

• Wydajność: maksymalizowanie szybkości działania programów

• Przenośność: pisanie programów, które działają wszędzie bez żadnych zmian

• Notacja: wybór języków i narzędzi, które pozwalają maszynie zrobić więcej

Stwórz swój własny kod w najlepszym stylu!

Spis tre�ci

Wst�p 7

1. Styl 111.1. Nazwy 131.2. Wyra�enia i instrukcje 161.3. Spójno�� i idiomy 201.4. Makra w roli funkcji 281.5. Liczby magiczne 291.6. Komentarze 331.7. Dlaczego warto dba� o styl? 38

2. Algorytmy i struktury danych 392.1. Przeszukiwanie 402.2. Sortowanie 422.3. Biblioteki 442.4. Sortowanie szybkie w Javie 472.5. Notacja O 502.6. Tablice rozszerzalne 512.7. Listy 542.8. Drzewa 592.9. Tablice mieszania 642.10. Podsumowanie 68

3. Projektowanie i implementacja 693.1. Algorytm �a�cucha Markowa 703.2. Wybór struktury danych 723.3. Budowa struktury danych w j�zyku C 733.4. Generowanie tekstu 773.5. Java 793.6. C++ 833.7. Awk i Perl 863.8. Wydajno�� 883.9. Wnioski 89

4 SPIS TRE�CI

4. Interfejsy 934.1. Warto�ci oddzielane przecinkami 944.2. Prototyp biblioteki 954.3. Biblioteka dla innych 994.4. Implementacja w j�zyku C++ 1084.5. Zasady projektowania interfejsów 1124.6. Zarzdzanie zasobami 1144.7. Obs�uga b��dów 1174.8. Interfejsy u�ytkownika 121

5. Usuwanie b��dów 1255.1. Programy diagnostyczne 1265.2. Dobre pomys�y, �atwe b��dy 1275.3. Brak pomys�ów, trudne b��dy 1315.4. Ostatnia deska ratunku 1355.5. B��dy niepowtarzalne 1385.6. Narz�dzia diagnostyczne 1405.7. B��dy pope�nione przez innych 1435.8. Podsumowanie 144

6. Testowanie 1476.1. Testuj kod podczas jego pisania 1486.2. Systematyczne testowanie 1536.3. Automatyzacja testów 1576.4. Ramy testowe 1596.5. Testowanie przeci�eniowe 1636.6. Porady dotyczce testowania 1666.7. Kto zajmuje si� testowaniem 1676.8. Testowanie programu markov 1686.9. Podsumowanie 170

7. Wydajno�� 1717.1. Wskie gard�o 1727.2. Mierzenie czasu wykonywania i profilowanie programu 1777.3. Strategie przyspieszania 1817.4. Regulowanie kodu 1847.5. Oszcz�dzanie pami�ci 1887.6. Szacowanie 1917.7. Podsumowanie 193

8. Przeno�no�� 1958.1. J�zyk 1968.2. Nag�ówki i biblioteki 2028.3. Organizacja programu 2048.4. Izolacja 2088.5. Wymiana danych 2098.6. Kolejno�� bajtów 2108.7. Przeno�no�� a uaktualnianie 2138.8. Internacjonalizacja 2158.9. Podsumowanie 218

SPIS TRE�CI 5

9. Notacja 2219.1. Formatowanie danych 2229.2. Wyra�enia regularne 2289.3. Programowalne narz�dzia 2349.4. Interpretery, kompilatory i maszyny wirtualne 2379.5. Programy, które pisz programy 2429.6. Generowanie kodu za pomoc makr 2469.7. Kompilacja w locie 247

A Epilog 253

B Zebrane zasady 255

Skorowidz 259

5Usuwanie b��dów

bug

b. Usterka lub b��d w maszynie, planie itp. poch. USA. 11 marca 1889 Pall Mall Gaz. 1/1: Powiadomionomnie, �e pan Edison nie �pi ju� od dwóch dni, próbuj�c znale� usterk� (ang. bug) w swoim fonografie— wyra�enie oznaczaj�ce poszukiwanie rozwi�zania problemu i sugeruj�ce, �e gdzie� wewn�trz ukry�si� wyimaginowany insekt, który powoduje trudno�ci.

Oxford English Dictionary, wyd. 2.

W poprzednich czterech rozdzia�ach przedstawili�my sporo przyk�adów kodu i za ka�dym razemudawali�my, �e wszystkie one od razu prawid�owo dzia�a�y. Oczywi�cie tak nie by�o — w ka�-dym z nich pocztkowo a� roi�o si� od b��dów. S�owo bug mimo i� nie powsta�o w �rodowiskuprogramistycznym, jest niewtpliwie jednym z najcz��ciej u�ywanych s�ów w tej dziedzinie.Dlaczego tworzenie oprogramowania jest takie trudne?

Jednym z powodów jest to, �e na z�o�ono�� programów ma wp�yw liczba interakcji wyst�-pujcych mi�dzy ich sk�adnikami, a programy s pe�ne sk�adników i relacji. Istnieje wieletechnik s�u�cych do zmniejszania liczby powiza� mi�dzy komponentami. Zalicza si� do nichukrywanie informacji, abstrakcj� i interfejsy oraz w�a�ciwo�ci j�zyka, które s�u� do ich reali-zowania. S równie� techniki zapewniajce integralno�� projektów programów — dowodzeniepoprawno�ci programów, modelowanie, analiza wymaga�, formalna weryfikacja — ale �adnaz nich nie zmieni�a sposobu, w jaki tworzy si� oprogramowanie. Wszystkie okaza�y si� sku-teczne tylko w rozwizywaniu bardzo ma�ych problemów. Rzeczywisto�� jest taka, �e zawszeznajd si� b��dy, które b�dziemy wykrywa� za pomoc testowania i eliminowa� za pomoctechnik usuwania b��dów (ang. debugging).

Dobry programista wie, �e usuwanie b��dów zajmuje tyle samo czasu, co pisanie kodu,i dlatego zawsze stara si� wyciga� z nich wnioski. Ka�dy wykryty b�d jest nauk na przysz�o��,jak unikn� powtórki takiej sytuacji lub jak rozpozna�, �e mia�a ona miejsce.

Usuwanie b��dów to trudna i nieprzewidywalnie czasoch�onna sztuka, dlatego nale�y zro-bi� wszystko, aby mie� z ni jak najmniej do czynienia. Sposobów na skrócenie czasu usuwaniausterek jest wiele, np. staranne opracowywanie projektu, pisanie w dobrym stylu, sprawdzanie

126 5. USUWANIE B�DÓW

warunków brzegowych, stosowanie asercji i testów sensowno�ci, programowanie defensywne,projektowanie dobrych interfejsów, ograniczanie ilo�ci danych globalnych oraz korzystaniez narz�dzi diagnostycznych. Profilaktyka zawsze jest lepsza od leczenia.

Jaka jest rola j�zyka? Najwi�ksz si� od zawsze kszta�tujc ewolucj� j�zyków programo-wania jest ch�� zapobiegania wyst�powaniu b��dów poprzez odpowiednie dobranie w�a�ciwo�cij�zyka. Niektóre cechy j�zyków programowania pozwalaj wyeliminowa� ca�e grupy b��dów, np.sprawdzanie zakresu w operacjach indeksowania, ograniczenie lub wr�cz wy�czenie mo�liwo�cistosowania wska�ników, automatyczne odzyskiwanie pami�ci, �a�cuchowe typy danych, kon-trola typów wej�cia-wyj�cia i rygorystyczna kontrola typów. Z drugiej strony pewne w�asno�cij�zyków zwi�kszaj prawdopodobie�stwo powstawania b��dów: instrukcje goto, zmienne globalne,nieograniczony dost�p do wska�ników i automatyczne konwersje typów. Programi�ci powinniwiedzie�, które w�a�ciwo�ci j�zyka s potencjalnie ryzykowne, i zachowa� szczególn ostro�-no�� przy ich u�ywaniu. Ponadto powinni w�czy� wszystkie narz�dzia diagnostyczne kom-pilatora i zwraca� uwag� na zg�aszane przez niego ostrze�enia.

W�a�ciwo�ci j�zykowe, które uniemo�liwiaj powstawanie pewnych b��dów, maj swoj cen�.Je�li j�zyk programowania wysokiego poziomu automatycznie usuwa niektóre b��dy, cen jestto, �e �atwiej jest nam pope�nia� b��dy wy�szego poziomu. aden j�zyk nie sprawi, �e ca�kiemprzestaniemy pope�nia� b��dy.

Chocia� woleliby�my, aby by�o inaczej, ka�dy programista najwi�cej czasu sp�dza na testo-waniu kodu i usuwaniu b��dów. W tym rozdziale omówimy techniki produktywnego i szyb-kiego usuwania b��dów. Do testowania wrócimy jeszcze w rozdziale 6.

5.1. Programy diagnostyczneKompilatory najwa�niejszych j�zyków programowania s wyposa�one w zaawansowane pro-gramy diagnostyczne (ang. debugger). Narz�dzia takie wchodz w sk�ad wielu zintegrowanych�rodowisk programistycznych oferujcych w jednym pakiecie narz�dzia do pisania i edytowa-nia kodu, kompilacji oraz wykonywania utworzonych programów. Programy diagnostycznemaj graficzne interfejsy, za pomoc których mo�na wykonywa� kod programu po jednej in-strukcji lub funkcji albo zatrzymywa� wykonywanie po wykonaniu okre�lonych wierszy lubspe�nieniu zdefiniowanych warunków. Ponadto oferuj mo�liwo�� formatowania i wy�wietla-nia bie�cych warto�ci zmiennych.

Program diagnostyczny mo�na uruchomi� bezpo�rednio, je�li wiadomo, �e wystpi� b�d.Niektóre takie programy automatycznie przejmuj sterowanie, gdy wykryj, i� co� si� nie po-wiod�o w czasie wykonywania programu. Zwykle wykrycie miejsca wystpienia b��du jest nie-trudne. W tym celu nale�y tylko sprawdzi� sekwencj� funkcji, które by�y w tym czasie wykonywane(stos wywo�a) oraz wy�wietli� warto�ci zmiennych lokalnych i globalnych. Tyle informacjicz�sto wystarcza do znalezienia �ród�a problemu. Je�li to zawiedzie, mo�na skorzysta� z punk-tów wstrzymania i funkcji wykonywania programu krok po kroku, aby znale�� miejsce, w którympo raz pierwszy wystpi�y jakie� anomalie.

W r�kach do�wiadczonego programisty korzystajcego z dobrego �rodowiska program dia-gnostyczny mo�e by� bardzo efektywnym i wydajnym narz�dziem, które pozwala zaoszcz�dzi�mnóstwo nerwów. Skoro dost�pne s tak wspania�e narz�dzia, po co kto� mia�by usuwa� b��dy,nie korzystajc z ich pomocy? Po co usuwaniu b��dów po�wi�ca� a� ca�y rozdzia�?

Istnieje ku temu kilka dobrych powodów, zarówno obiektywnych, jak i wynikajcych z na-szego osobistego do�wiadczenia. Dla niektórych j�zyków spoza g�ównego nurtu nie ma �adne-go programu diagnostycznego albo, je�eli jest, jego funkcjonalno�� jest bardzo ograniczona.

5.2. DOBRE POMYS�Y, �ATWE B�DY 127

Ponadto dzia�anie narz�dzi diagnostycznych zale�y od systemu operacyjnego, a wi�c nie zaw-sze mo�esz mie� dost�p do swoich ulubionych programów tego rodzaju. Programy diagno-styczne s�abo radz sobie z niektórymi rodzajami programów, np. wieloprocesowymi i wielowt-kowymi, systemami operacyjnymi i systemami rozproszonymi. W takich przypadkach koniecznejest u�ycie technik ni�szego poziomu. Programista jest wówczas zdany na siebie, do dyspozycjima tylko instrukcje drukujce oraz w�asne do�wiadczenie i umiej�tno�� analizowania kodu.

Osobi�cie staramy si� nie nadu�ywa� programów diagnostycznych i ograniczamy si� dosprawdzenia za ich pomoc stosu wywo�a� oraz warto�ci paru zmiennych. Jednym z powodówpodj�cia takiej decyzji jest to, �e mo�na bardzo �atwo pogubi� si� w skomplikowanej pltaniniestruktur danych i �cie�ek wykonawczych. Naszym zdaniem wykonywanie kodu krok po krokujest mniej produktywne ni� jego dok�adniejsze przeanalizowanie oraz dodanie kilku instrukcjiwyj�ciowych i samosprawdzajcego si� kodu w krytycznych miejscach. Na przejrzenie danychzwróconych przez kilka roztropnie rozmieszczonych instrukcji drukujcych potrzeba mniejczasu ni� na wykonywanie kolejnych instrukcji za pomoc klikni�� mysz. Podj�cie decyzji,gdzie wstawi� instrukcj� drukowania, zajmuje mniej czasu ni� przechodzenie do krytycznegofragmentu kodu po jednej instrukcji, nawet je�li dok�adnie wiadomo, które to miejsce. Cowa�niejsze, instrukcje diagnostyczne pozostaj w programie, a sesje programu diagnostycznegoznikaj.

Szukanie b��dów po omacku za pomoc programu diagnostycznego rzadko bywa produk-tywne. O wiele lepiej jest u�y� go do sprawdzenia stanu programu w chwili wystpienia usterkii na podstawie zdobytych informacji zastanowi� si�, jak mog�o do tej sytuacji doj��. Programydiagnostyczne bywaj niezwykle skomplikowane i trudne do opanowania. Zw�aszcza poczt-kujcy programista mo�e mie� z nich sto pociech i tysic utrapie�. Je�li programowi diagno-stycznemu zada si� niew�a�ciwe pytanie, to zwykle zwróci on odpowied�, ale nie wiadomo, czypoprawn.

Mimo to program diagnostyczny mo�e by� niezwykle pomocny i ka�dy programista powinienmie� go pod r�k. W wielu przypadkach jest to pierwsze narz�dzie, z którego pomocy si� ko-rzysta. Je�li jednak nie masz programu diagnostycznego albo napotkasz wyjtkowo trudny dorozwizania problem, dzi�ki technikom opisanym w tym rozdziale i tak szybko wyjdziesz z opresji.Ponadto nauczysz si� dzi�ki nim efektywniej korzysta� z programów diagnostycznych, gdy�dotycz tego, jak analizowa� b��dy i szuka� ich prawdopodobnych przyczyn.

5.2. Dobre pomys�y, �atwe b��dyOho! Co� jest nie tak. Mój program pad�, wydrukowa� bzdury albo nie chce przesta� dzia�a�.Co robi�?

Pocztkujcy programi�ci w takich sytuacjach najcz��ciej zrzucaj win� na kompilator, bi-bliotek� i wszystko, tylko nie ich kod. Do�wiadczeni programi�ci te� by tak chcieli, ale b�dcrealistami, doskonale wiedz, �e wi�kszo�� b��dów powstaje wy�cznie z ich winy.

Na szcz��cie g�ównie robimy proste b��dy, które mo�na wyeliminowa� prostymi technikami.Przeanalizuj zwrócone przez program b��dne dane i spróbuj wywnioskowa�, w jaki sposób mog�ypowsta�. Przejrzyj dane diagnostyczne wyprodukowane przed wystpieniem awarii. Je�li masztak mo�liwo��, sprawd� stos wywo�a�. Po wykonaniu tych czynno�ci b�dziesz ju� mie� jakie�poj�cie na temat tego, co i gdzie si� sta�o. Przemy�l to. Jak mog�o do tego doj��? Przeanalizujzachowanie programu od pocztku i zastanów si�, co mog�o spowodowa� jego wadliwe dzia�anie.

Diagnostyka b��dów wymaga analizowania w my�lach przesz�o�ci, podobnie jak wykrywa-nie sprawców morderstw. Zdarzy�o si� co� niemo�liwego, a jedyna informacja, jak posiadamy,

128 5. USUWANIE B�DÓW

to fakt, �e rzeczywi�cie mia�o to miejsce. Aby odkry� przyczyn� problemów, musimy si� cofn�w czasie. Po znalezieniu pe�nego wyja�nienia b�dziemy wiedzie�, jak naprawi� program, a przyokazji prawdopodobnie odkryjemy jeszcze kilka innych rzeczy, których si� nie spodziewali�my.

Szukaj znajomych wzorców. Odpowiedz sobie na pytanie, czy ju� co� takiego widzia�e�. Od-powied� typu „Gdzie� ju� to widzia�em” zwykle stanowi pierwszy krok do zrozumienia, a nie-jednokrotnie oznacza nawet rozwizanie. Cz�sto wyst�pujce b��dy maj pewne cechy szcze-gólne. Przyk�adowo pocztkujcy programi�ci cz�sto pisz tak:

? int n;? scanf("%d", n);

zamiast tak:

int n;scanf("%d", &n);

co zwykle ko�czy si� prób odczytu danych z miejsca poza wyznaczonym obszarem pami�-ci przy pobieraniu wiersza danych wej�ciowych. Wyk�adowcy j�zyka C natychmiast rozpoznajten problem.

Niewyczerpanym �ród�em prostych b��dów s �le dobrane typy danych i ich konwersjew funkcjach printf i scanf:

? int n = 1;? double d = PI;? printf("%d %f\n", d, n);

Znakiem szczególnym tego rodzaju b��du jest czasami pojawienie si� niedorzecznych war-to�ci: wielkich liczb ca�kowitych albo niewiarygodnie ma�ych lub du�ych warto�ci zmienno-przecinkowych. Powy�szy program uruchomiony na komputerze SPARC firmy Sun zwróci�nast�pujc astronomiczn liczb� (z konieczno�ci podzielon na kilka wierszy):

1074340347 268156158598852001534108794260233396350\ 1936585971793218047714963795307788611480564140\ 0796821289594743537151163524101175474084764156\ 422771408323839623430144.000000

Kolejny pospolity b�d dotyczy wczytywania liczb typu double za pomoc funkcji scanfprzy u�yciu cigu %f zamiast %lf. Niektóre kompilatory wy�apuj takie b��dy, poniewa�sprawdzaj zgodno�� typów argumentów funkcji scanf i printf z �a�cuchami formatu. Przyw�czonych wszystkich ostrze�eniach kompilator gcc w systemie GNU dla powy�szego wywo-�ania funkcji printf zwróci nast�pujce informacje:

x.c:9: warning: int format, double arg (arg 2)x.c:9: warning: double format, different type arg (arg 3)

Kolejny rodzaj b��du, który �atwo rozpozna� po znakach szczególnych, to brak inicjalizacjizmiennej lokalnej. Wynikiem tego zaniedbania jest zwykle nies�ychanie du�a warto��, b�dcapozosta�o�ci po tym, co uprzednio znajdowa�o si� w tym miejscu w pami�ci. Niektóre kompi-latory mog przestrzega� przed takimi b��dami, aczkolwiek do tego konieczne mo�e by� w�-

5.2. DOBRE POMYS�Y, �ATWE B�DY 129

czenie opcji sprawdzania podczas kompilacji, a poza tym — �aden kompilator nie wychwyciwszystkiego. Tak�e pami�� alokowana za pomoc takich funkcji, jak malloc, realloc i new,mo�e by� bezu�yteczna, je�li nie zostanie zainicjalizowana.

Przeanalizuj ostatni� zmian�. Jakie zmiany w programie zosta�y ostatnio wprowadzone? Je�lirozwijajc program, za ka�dym razem dodajesz do niego tylko jedn rzecz, to s wy�cznie dwiemo�liwo�ci: nowy kod spowodowa� wystpienie b��du albo ujawni� b�d w starym kodzie.W znalezieniu problemu pomocne jest dok�adne przejrzenie ostatnich zmian. Je�li b�d wyst�-puje w nowej wersji programu, a nie ma go w starszej, to nowy kod jest cz��ci problemu. Dla-tego trzeba zawsze zachowywa� przynajmniej poprzedni wersj� programu, aby w razie k�opo-tów móc porówna� zachowanie z najnowsz wersj. Ponadto nale�y prowadzi� rejestrwprowadzanych zmian i naprawianych b��dów, by nie musie� zdobywa� tych informacji nanowo, gdy trzeba b�dzie naprawi� kolejny b�d. Pomocne s w tym systemy kontroli kodu �ró-d�owego i inne techniki �ledzenia historii zmian.

Nie pope�niaj dwukrotnie tego samego b��du. Gdy naprawisz jaki� b�d, zastanów si�, czy niemóg� on wystpi� jeszcze gdzie� indziej. Taka sytuacja przydarzy�a si� jednemu z nas krótkoprzed rozpocz�ciem pisania tego rozdzia�u. Mia�o to miejsce w prostym, pisanym dla kolegiprototypie przedstawiajcym schemat obs�ugi opcjonalnych argumentów:

? for (i = 1; i < argc; i++) {? if (argv[i][0] != '-') /* Koniec opcji */? break;? switch (argv[i][1]) {? case 'o': /* Nazwa pliku wyj�ciowego */? outname = argv[i];? break;? case 'f':? from = atoi(argv[i]);? break;? case 't':? to = atoi(argv[i]);? break;? ...

Nied�ugo po wypróbowaniu programu kolega poinformowa� nas, �e do nazwy pliku zawszedo�czany by� przedrostek -o. By�o nam wstyd, ale b�d okaza� si� �atwy do naprawienia. Po-prawili�my jedn instrukcj�:

outname = &argv[i][2];

Po naprawieniu tego b��du i odes�aniu programu do u�ytkownika niebawem przysz�a ko-lejna wiadomo��. Tym razem program niepoprawnie obs�ugiwa� argumenty typu -f123: pokonwersji warto�� liczbowa zawsze wynosi�a zero. To ten sam b�d, co wcze�niej. Poprawili�myzatem nast�pn klauzul� case:

from = atoi(&argv[i][2]);

Poniewa� autor si� spieszy�, nie zauwa�y�, �e ten sam b�d wyst�powa� jeszcze w dwóch in-nych miejscach, przez co zanim uda�o si� ostatecznie oczy�ci� program z kilku wystpie� iden-tycznego b��du, potrzebna by�a jeszcze jedna wymiana do�wiadcze� z naszym koleg.

130 5. USUWANIE B�DÓW

W �atwym kodzie nietrudno pope�ni� b�d, poniewa� widzc znany problem, przestajemyby� ostro�ni. Nawet je�li kod jest tak prosty, �e móg�by� go napisa� z zamkni�tymi oczami, lepiejnie zamykaj oczu podczas jego pisania.

Nie odk�adaj poprawiania b��dów na pó�niej. Po�piech przy wykonywaniu pracy mo�e mie�szkodliwe skutki tak�e w innych sytuacjach. Nigdy nie ignoruj awarii. Zawsze od razu poprawb�d, bo mo�e si� nie powtórzy�, a� b�dzie za pó�no. S�ynny sta� si� przyk�ad takiego niedopa-trzenia w misji sondy „Pathfinder” wys�anej na Marsa. Po jej pomy�lnym ldowaniu na po-wierzchni planety w lipcu 1997 roku komputery pok�adowe resetowa�y si� mniej wi�cej raz nadzie�, co stanowi�o wielk zagadk� dla in�ynierów. Gdy znale�li przyczyn� problemów, zdalisobie spraw�, �e mieli ju� z tym do czynienia. Takie zachowania komputerów zdarza�y si� ju�w fazie wst�pnych testów, ale zosta�y zlekcewa�one, poniewa� in�ynierowie pracowali wówczasnad czym� innym. Zostali wi�c zmuszeni do zaj�cia si� tym dopiero pó�niej, gdy maszynaznajdowa�a si� miliony kilometrów od nich i znacznie trudniej by�o j naprawi�.

Sprawdzaj stos wywo�a. Mimo i� programy diagnostyczne pozwalaj bada� programy pod-czas dzia�ania, to najcz��ciej s wykorzystywane do analizowania stanu programu, który prze-sta� dzia�a�. Do najbardziej przydatnych informacji dostarczanych przez program diagnostycz-ny nale�y numer wiersza kodu �ród�owego, w którym wystpi� problem. Cenn wskazówk srównie� nieprawdopodobne warto�ci argumentów (puste wska�niki, bardzo du�e warto�ci ca�-kowite, podczas gdy spodziewane s ma�e, ujemne warto�ci tam, gdzie powinny by� dodatnie,�a�cuchy znaków nienale�cych do alfabetu).

Oto typowy przyk�ad z opisu algorytmów sortowania przedstawionego w rozdziale 2. Abyposortowa� tablic� liczb ca�kowitych, nale�y wywo�a� funkcj� qsort, przekazujc jej jako ar-gument funkcj� icmp porównujc liczby ca�kowite:

int arr[N];qsort(arr, N, sizeof(arr[0]), icmp);

Za�ó�my, �e pomy�kowo podano nazw� scmp funkcji porównujcej �a�cuchy:

? int arr[N];? qsort(arr, N, sizeof(arr[0]), scmp);

Jako �e kompilator w tym przypadku nie mo�e wykry� niezgodno�ci typów, nieuchronnienapytali�my sobie biedy. Program ulega awarii spowodowanej prób dost�pu do niedozwolo-nego miejsca w pami�ci. Program diagnostyczny dbx zwraca nast�pujce informacje o stosiewywo�a� (przeredagowane, aby zmie�ci�y si� na stronie):

0 strcmp(0xla2, 0xlc2) ["strcmp.s":31]1 scmp(p1 = 0x10001048, p2 = 0x1000105c) ["badqs.c":13]2 qst(0x10001048, 0x10001074, Ox400b20, 0x4) ["qsort.c":147]3 qsort(0x10001048, 0xlc2, 0x4, 0x400b20) ["qsort.c":63]4 main() ["badqs.c":45]5 __istart() ["crt1tinit.s":13]

Z tych danych wynika, �e awaria nastpi�a w funkcji strcmp. Wida�, �e przekazywane doniej dwa wska�niki s o wiele za ma�e, co niewtpliwie jest oznak k�opotów. W stosie wywo�a�zosta�y podane orientacyjne numery wierszy, w których nastpi�o wywo�anie ka�dej funkcji.Wiersz nr 13 w naszym pliku badqs.c zawiera takie wywo�anie:

5.3. BRAK POMYS�ÓW, TRUDNE B�DY 131

return strcmp(v1, v2);

wskazujce na �ród�o b��du.Przy u�yciu programu diagnostycznego mo�na równie� wy�wietli� warto�ci zmiennych lo-

kalnych i globalnych, które tak�e mog naprowadzi� nas na jaki� trop.Najpierw przeczytaj, a potem poprawiaj. Jedn z najbardziej niedocenianych efektywnychtechnik wykrywania b��dów jest uwa�ne przeczytanie kodu i zastanowienie si� nad nim bez do-konywania jakichkolwiek zmian. Pokusa, aby chwyci� za klawiatur� i zacz� wprowadza� zmiany,jest bardzo du�a, ale nale�y si� jej oprze�. Istnieje du�e ryzyko, �e w ten sposób nie dowiesz si�,co tak naprawd� szwankuje, i zmienisz nie to, co trzeba, pogarszajc jeszcze tylko sytuacj�. Za-pisanie najwa�niejszej cz��ci programu na papierze pozwala spojrze� na niego z nieco innejperspektywy, ni� ogldajc go na ekranie, i zach�ca do refleksji. Nie stosuj jednak tej technikirutynowo. Drukowanie kodu programu to marnotrawstwo drzew, a poza tym i tak trudnoogarn� ca� struktur� kodu, je�li zajmuje on kilka stron. Co wi�cej, po wprowadzeniu pierw-szej zmiany ca�y wydruk nadaje si� do wyrzucenia.

Zrób sobie krótk przerw�. Czasami w kodzie widzisz to, co chcia�by� widzie�, a nie to, cojest w nim rzeczywi�cie zapisane. Je�li na chwil� si� oderwiesz, to po powrocie mo�e zacznieszwi�cej uwagi zwraca� na prawdziwe znaczenie kodu.

Oprzyj si� pokusie poprawiania kodu natychmiast. Warto chwil� si� przed tym zastanowi�.

Obja�nij swój kod komu� innemu. Dobrym sposobem jest obja�nienie napisanego przez siebiekodu innej osobie. Zdarza si�, �e w ten sposób sami odkrywamy sedno problemu. Czasami wy-starczy tylko powiedzie� kilka zda�, aby stwierdzi� ze wstydem: „Niewa�ne, ju� wiem, co jestnie tak. Przepraszam, �e Ci przeszkadzam”. To niezwykle skuteczna metoda. W rol� s�uchaczamo�e si� wcieli� nawet osoba nieb�dca programist. W pewnym uniwersyteckim o�rodkukomputerowym przy stanowisku pracy pomocy technicznej umieszczono pluszowego misia.Studenci chccy uzyska� pomoc najpierw musieli swój problem obja�ni� misiowi i dopiero po-tem mogli porozmawia� z cz�owiekiem.

5.3. Brak pomys�ów, trudne b��dy„Nie mam zielonego poj�cia, o co mo�e chodzi�”. Je�li kompletnie nie wiesz, w czym mo�etkwi� problem, to zaczynaj si� schody.

Wymu� powtarzalno�� b��du. Pierwsz czynno�ci, któr nale�y wykona�, jest sprawienie,aby b�d pojawia� si� na �danie. Tropienie b��du pojawiajcego si� tylko raz na jaki� czas niejest przyjemne. Po�wi�� chwil� na sporzdzenie danych wej�ciowych i opracowanie takich pa-rametrów, które pozwol Ci niezawodnie spowodowa� wystpienie b��du za ka�dym razem.Nast�pnie zapakuj to wszystko w jeden pakiet, aby móc go przywo�ywa� jednym przyciskiemalbo kilkoma klawiszami. Je�li b�d jest trudny do wytropienia, czynno�ci te trzeba b�dzie po-wtórzy� wielokrotnie, a wi�c lepiej je sobie maksymalnie upro�ci�.

Je�li b��du nie da si� odtworzy� za ka�dym razem, spróbuj zrozumie� dlaczego. Czy cz�sto-tliwo�� jego wyst�powania zale�y od jakich� specyficznych warunków? Nawet je�eli nie mo�eszwymusi� pojawienia si� b��du za ka�dym razem, warto spróbowa� przynajmniej skróci� czasoczekiwania na jego wystpienie.

Je�li program mo�e dostarcza� danych diagnostycznych, skorzystaj z tej mo�liwo�ci. Pro-gramy symulacyjne, takie jak program generujcy �a�cuchy Markowa z rozdzia�u 3., powinnyzawiera� opcj� generowania danych diagnostycznych, np. w celu sprawdzenia warto�ci pocztkowej

132 5. USUWANIE B�DÓW

generatora liczb losowych, dzi�ki którym mo�na spróbowa� odtworzy� uzyskane wyniki. Wieleprogramów zawiera takie opcje i warto je uwzgl�dni� tak�e w swoich programach.

Dziel i rz�d�. Czy dane wej�ciowe wywo�ujce awari� programu mo�na jako� zmniejszy� albobardziej skoncentrowa�? Stwórz minimalny zestaw danych wej�ciowych, które powoduj wy-st�powanie b��du, aby zredukowa� liczb� mo�liwo�ci. Jakie zmiany powoduj, �e b�d przestajesi� pokazywa�? Spróbuj wyodr�bni� takie przypadki testowe, które precyzyjnie koncentruj si�na szukanym b��dzie. Ka�dy taki przypadek powinien by� zaplanowany na uzyskanie okre�lone-go wyniku, potwierdzajcego lub wykluczajcego pewn hipotez� na temat �ród�a problemów.

U�yj algorytmu przeszukiwania binarnego. Odrzu� po�ow� danych wej�ciowych i sprawd�,czy program nadal zwraca niepoprawny wynik. Je�li nie, wró� do poprzedniego stanu i odrzu�drug po�ow� danych wej�ciowych, a pierwsz tym razem pozostaw. T� sam metod� mo�nazastosowa� w odniesieniu do tekstu programu. Usu� jak� cz��� kodu �ród�owego, która Twoimzdaniem nie powinna mie� zwizku z wyst�pujcym b��dem, i sprawd�, co si� stanie. Przy ma-nipulowaniu du�ymi przypadkami testowymi i du�ymi ilo�ciami kodu �ród�owego programubardzo pomocny jest edytor kodu z opcj cofania zmian, która zapewnia, �e nie utracimy b��du.

Przeprowad� numeryczn� analiz� usterek. Czasami na trop b��du mo�na wpa��, analizujcpewne liczbowe cechy usterki. Po napisaniu jednego z podrozdzia�ów tej ksi�ki spostrzegli-�my, �e niektóre litery gdzie� si� z niego ulotni�y. To by�o bardzo dziwne. Poniewa� tekst zo-sta� skopiowany i wklejony do pliku z innego miejsca, doszli�my do wniosku, �e problem tkwiw funkcji kopiowania lub wklejania edytora tekstu. Ale od czego rozpocz� poszukiwanie b��-du? Postanowili�my dok�adniej przyjrze� si� danym i odkryli�my, �e braki znaków wyst�pujw równych odst�pach w tek�cie. Obliczyli�my, �e odleg�o�� mi�dzy dwoma kolejnymi brakamizawsze wynosi�a 1 023 bajty. Taka regularno�� jest bardzo podejrzana. Poszukali�my w kodzie�ród�owym edytora warto�ci zbli�onych do 1 024 i znale�li�my kilka rzeczy wartych uwagi.Jedna z nich znajdowa�a si� w �wie�o napisanym kodzie, a wi�c postanowili�my zacz� od niej.Szybko spostrzegli�my b�d. By�a to klasyczna pomy�ka o jeden, która powodowa�a, �e zerowybajt kasowa� ostatni znak w buforze o rozmiarze 1 024 bajtów.

Na trop b��du wpadli�my dzi�ki przeanalizowaniu liczbowych w�a�ciwo�ci zwizanych z uster-k. Ile czasu nam to zaj��o? Kilka minut sp�dzili�my w os�upieniu, pi�� minut zaj��o nam od-krycie prawid�owo�ci w znikaniu znaków i kolejnych pi�ciu minut potrzebowali�my na znale-zienie i usuni�cie b��du. Rozwizanie tego problemu przy u�yciu programu diagnostycznegoby�oby bardzo trudne, gdy� w gr� wchodzi�y dwa wieloprocesowe programy obs�ugiwane zapomoc myszy i komunikujce si� ze sob poprzez system plików.

Wy�wietlaj dodatkowe informacje, aby zorientowa� si�, jak dzia�a program. Je�li nie rozu-miesz, co robi kod, to naj�atwiejszym i najmniej kosztownym wydajno�ciowo sposobem na do-wiedzenie si� tego jest dodanie instrukcji wy�wietlajcych ró�ne informacje. W ten sposóbmo�na upewni� si� co do s�uszno�ci swoich ocen lub zweryfikowa� hipotezy na temat tego, codzia�a �le. Je�li np. wydaje Ci si�, �e niemo�liwe jest dotarcie do pewnej cz��ci kodu, dodaj in-strukcj� wy�wietlajc informacj�: „Nie mo�na tu wej��”. Je�eli pó�niej komunikat ten zosta-nie pokazany, przesu� wy�wietlajc go instrukcj� nieco wy�ej, aby dowiedzie� si�, w którymmiejscu zaczynaj si� k�opoty. Analogicznie mo�esz te� wy�wietla� informacj�: „Uda�o si� tuwej��” i przesuwa� j stopniowo coraz dalej, by znale�� ostatnie miejsce, w którym nic z�ego si�nie dzieje. Komunikaty powinny ró�ni� si� od siebie, aby za ka�dym razem by�o wiadomo,który zosta� wy�wietlony.

Komunikaty powinny by� zwi�z�e i zawsze mie� jednakowy format, aby dawa�y si� �atwoprzeanalizowa� programi�cie lub programom pomocniczym, takim jak np. narz�dzie grep s�u-�ce do porównywania wzorców. Programy podobne do grep s nieocenionym wsparciem przy

5.3. BRAK POMYS�ÓW, TRUDNE B�DY 133

przeszukiwaniu tekstu — prost implementacj� takiego narz�dzia przedstawiamy w rozdziale 9.Je�li wy�wietlasz warto�ci zmiennych, to za ka�dym razem formatuj komunikat w taki samsposób. W j�zykach C i C++ wska�niki prezentuj w postaci liczb szesnastkowych przy u�yciuspecyfikatorów formatu %x lub %p. Dzi�ki temu dowiesz si�, czy dwa wska�niki maj t� samwarto�� bd� s ze sob w jaki� sposób powizane. Naucz si� odczytywa� warto�ci wska�nikóworaz rozpoznawa� prawdopodobne i nieprawdopodobne warto�ci, np. zero, liczby ujemne, nie-typowe warto�ci i ma�e liczby. Tak�e znajomo�� formatów adresów przydaje si� podczas u�y-wania programu diagnostycznego.

Je�li jest mo�liwo��, �e program zwróci bardzo du� ilo�� danych, to mo�e dane te wystar-czy wydrukowa� w postaci pojedynczych liter, np. A, B itd., aby zwi��le pokaza�, dokd pro-gram doszed�.

Pisz samosprawdzaj�cy si� kod. Je�li potrzebujesz wi�cej informacji, to mo�esz napisa� w�a-sn funkcj� sprawdzajc okre�lony warunek, wy�wietlajc warto�ci odpowiednich zmiennychi zamykajc program:

/* check: sprawdza warunek, drukuje i ko�czy dzia�anie */void check(char *s){ if (var1 > var2) { printf("%s: var1 %d var2 %d\n", s, var1, var2); fflush(stdout); /* Zapewnia wys�anie wszystkich danych na wyj�cie */ abort(); /* Sygnalizuje nienormalne zako�czenie dzia�ania programu */ }}

Funkcja check wywo�uje standardow funkcj� j�zyka C o nazwie abort, która przedwcze-�nie ko�czy dzia�anie programu w celu umo�liwienia jego analizy w programie diagnostycznym.Oczywi�cie funkcj� check mo�na te� zmieni� w taki sposób, aby po wydrukowaniu informacjinie zamyka�a programu.

Nast�pnie wywo�aj funkcj� check wsz�dzie tam, gdzie tego potrzebujesz:

check("Przed podejrzanym kodem");/* … Podejrzany kod … */check("Za podejrzanym kodem");

Po naprawieniu b��du nie usuwaj funkcji check z kodu �ród�owego. Umie�� j w komenta-rzu albo wy�cz j za pomoc opcji programu diagnostycznego, aby móc jej u�y� ponownie, gdywystpi kolejny trudny do rozwizania problem.

Je�li pojawi si� takie problemy, zakres obowizków funkcji mo�na rozszerzy� np. o weryfikacj�i wy�wietlanie struktur danych. Mo�na nawet zastosowa� bardziej ogólne podej�cie i napisa�procedur� na bie�co sprawdzajc spójno�� struktur danych i innych informacji. W programach,w których wykorzystywane s skomplikowane struktury danych, warto takie funkcje napisa�,zanim jeszcze pojawi si� problemy, i uczyni� je integraln cz��ci programu. Wówczas w raziek�opotów mo�na je bez przeszkód w�czy�. Nie ograniczaj si� do korzystania z nich tylko pod-czas usuwania b��dów. Mo�esz ich u�ywa� we wszystkich fazach rozwoju programu, a je�li niepoch�aniaj zbyt du�o zasobów, to nawet warto je pozostawi� w�czone ca�y czas. W du�ychprogramach, takich jak systemy komutacyjne w komunikacji, cz�sto znaczn cz��� kodu stanowipodprogramy monitorujce przep�ywajce informacje i sprz�t i zg�aszajce wszelkie usterki,niekiedy nawet automatycznie je naprawiajc.

134 5. USUWANIE B�DÓW

Utwórz dziennik. Kolejnym sposobem jest utworzenie pliku dziennika, w którym b�d zapi-sywane dane diagnostyczne w �ci�le okre�lonym formacie. W razie wystpienia awarii w plikutakim powinien znale�� si� zapis tego, co dzia�o si� tu� przed tym wydarzeniem. Serwery sie-ciowe i inne programy dzia�ajce w sieci utrzymuj dzienniki, w których zapisuj ogromne ilo�ciinformacji o ruchu sieciowym — na ich podstawie kontroluj siebie i swoich klientów. Poni�ejprzedstawiamy fragment takiego pliku pochodzcego z lokalnego systemu (tekst dopasowanydo strony):

[Sun Dec 27 16:19:24 1998]HTTPd: access to /usr/local/httpd/cgi-bin/test.html failed for m1.cs.bell-labs.com, reason: client denied by server (CGI non-executable) from http://m2.cs.bell-labs.com/cgi-bin/test.pl

Aby w pliku dziennika pojawi�y si� rekordy danych, trzeba pami�ta� o zapisaniu w nimzawarto�ci buforów wej�cia i wyj�cia. Funkcje wyj�ciowe, takie jak printf, zwykle buforujswoje wyniki, aby zoptymalizowa� dzia�anie operacji drukowania. Przy nienormalnym zako�-czeniu pracy programu informacje te mog zosta� utracone. W j�zyku C zapisanie wszystkichtego typu danych przed zamkni�ciem programu mo�na wymusi� za pomoc funkcji fflush. Jejodpowiednikiem w j�zykach C++ i Java jest funkcja flush zapisujca dane ze strumieni wyj-�ciowych. Je�eli nie przeszkadzaj Ci dodatkowe koszty wydajno�ciowe, problem mo�esz roz-wiza� raz na zawsze, wy�czajc buforowanie operacji zapisu danych w dzienniku. S�u� dotego standardowe funkcje o nazwach setbuf i setvbuf. Wywo�anie funkcji setbuf(fp, NULL)spowoduje wy�czenie buforowania w strumieniu fp. Standardowe strumienie b��dów (stderr,cerr i System.err) maj domy�lnie wy�czone buforowanie.

Rysuj obrazy. Czasami w testowaniu i usuwaniu b��dów doskona� pomoc s obrazy. Oczywi-�cie najbardziej pomagaj w zrozumieniu struktur danych, o czym przekonali�my si� w roz-dziale 2., i w pisaniu programów graficznych, ale to nie jedyne ich zastosowania. Na wykresiepunktowym lepiej wida� rozk�ad warto�ci ni� w kolumnach liczb. Na histogramie mo�na �a-twiej wychwyci� anomalie w ocenach z egzaminów, losowych liczbach, rozmiarach kube�kówalokowanych przez specjalne funkcje i u�ywanych w tablicach mieszania itd.

Je�li nie rozumiesz, co dzieje si� w Twoim programie, spróbuj sobie pomóc, opatrujcstruktury danych danymi statystycznymi, które dodatkowo przedstaw w postaci wykresu. Po-ni�ej zaprezentowano wykresy sporzdzone dla programu Markowa z rozdzia�u 3. w wersji na-pisanej w j�zyku C. Na o� x zosta�y naniesione d�ugo�ci �a�cuchów mieszania, a na o� y — licz-by elementów w tych �a�cuchach. Jako danych wej�ciowych u�yli�my naszego standardowegotekstu z Ksi�gi Psalmów (42 685 s�ów, 22 482 przedrostki). Pierwsze dwa wykresy zosta�y spo-rzdzone dla dobrych mno�ników 31 i 37, a trzeci — dla koszmarnej warto�ci 128. W dwóchpierwszych przypadkach d�ugo�� �adnego �a�cucha nie przekracza 15 lub 16 elementów, a wi�k-szo�� �a�cuchów sk�ada si� z 5 i 6 elementów. W trzecim przypadku dane s bardziej rozpro-szone, najd�u�szy �a�cuch ma 187 elementów i wyst�puje bardzo du�o �a�cuchów zawieraj-cych po 20 i wi�cej elementów.

5.4. OSTATNIA DESKA RATUNKU 135

Korzystaj z narz�dzi. Dobrze u�yj narz�dzi oferowanych przez swoje �rodowisko pracy. Naprzyk�ad program porównujcy pliki, taki jak diff, zestawia wyniki programu, którego wyko-nywanie zako�czy�o si� powodzeniem, i takiego, którego wykonywanie zako�czy�o si� niepo-wodzeniem, dzi�ki czemu mo�na przeanalizowa� ró�nice. Je�li program diagnostyczny zwracadu�e ilo�ci danych, to przeszukuj je za pomoc takiego programu jak grep oraz analizuj przyu�yciu edytora. Wstrzymaj si� od drukowania na papierze danych diagnostycznych: kompute-ry lepiej radz sobie z analiz du�ych ilo�ci danych ni� ludzie. U�yj skryptów pow�oki, abyzautomatyzowa� proces przetwarzania danych diagnostycznych.

Pisz proste programy do weryfikacji hipotez i swojego zrozumienia sposobu dzia�ania kodu.Czy mo�na np. zwolni� pusty wska�nik?

int main (void){ free(NULL); return 0;}

Programy do kontroli kodu �ród�owego, takie jak RCS, umo�liwiaj rejestracj� kolejnychwersji programu, dzi�ki czemu mo�na sprawdzi�, jakie zmiany zosta�y wprowadzone, i w raziepotrzeby przywróci� jedn ze starszych wersji. Oprócz funkcji podgldu najnowszych zmianprogramy te oferuj równie� mo�liwo�� znalezienia najcz��ciej modyfikowanych fragmentówkodu. W tych miejscach cz�sto kryj si� rozmaite b��dy.

Pisz dokumentacj�. Je�li poszukiwania �ród�a problemów b�d si� przeciga�, po pewnymczasie zapomnisz, co ju� zosta�o sprawdzone, a czego jeszcze nie wiesz. Je�eli zaczniesz zapisy-wa� wykonane testy i ich wyniki, to b�dziesz mie� pewno��, �e niczego nie przeoczysz. Notujcinformacje o problemie, lepiej zapami�tasz, �e kiedy� ju� co� podobnego widzia�e�, a przy oka-zji b�dziesz mie� pomoc, gdy zechcesz obja�ni� problem komu� innemu.

5.4. Ostatnia deska ratunkuCo robi�, je�li �adna z wymienionych technik nie pomaga? Teraz mo�e nadesz�a pora na wy-konanie programu krok po kroku w programie diagnostycznym. Je�li masz kompletnie b��dnewyobra�enie o tym, jak co� dzia�a, przez co szukasz problemu w niew�a�ciwym miejscu alboszukasz tam, gdzie trzeba, lecz go nie widzisz, program diagnostyczny mo�e zmusi� Ci� do

136 5. USUWANIE B�DÓW

spojrzenia na sprawy z innej perspektywy. B��dy niedajce si� wykry� z powodu niew�a�ciwegorozumienia istoty problemu s najgorsze. W takich przypadkach mechaniczna pomoc jest bez-cenna.

Czasami b��dne przekonanie dotyczy bardzo prostych zagadnie�, s to np.: niepoprawnakolejno�� wykonywania operatorów, u�ycie niew�a�ciwego operatora, wci�cia kodu niezgodnez jego struktur czy b��dy zakresu dost�pno�ci zmiennych polegajce na tym, �e zmienna lo-kalna zas�ania zmienn globaln albo zmienna globalna wcina si� w zakres lokalny. Programi-�ci cz�sto zapominaj przyk�adowo o tym, �e operatory & i | stoj dalej w kolejce do wykonaniani� operatory == i !=. Dlatego zdarza im si� pisa� taki kod:

? if (x & 1 == 0)? ...

i nie mog zrozumie�, dlaczego ten warunek nigdy nie jest spe�niony. Czasami po�lizgniesi� palec i omy�kowo zamiast jednego znaku równo�ci napisz si� dwa albo odwrotnie:

? while ((c == getchar()) != EOF)? if (c = '\n')? break;

Albo podczas pracy nad programem nie zostanie usuni�ty niepotrzebny kod:

? for (i = 0; i < n; i++);? a[i++] = 0;

Niektóre problemy wynikaj z po�piechu:

? switch (c) {? case '<':? mode = LESS;? break;? case '>':? mode = GREATER;? break;? defualt:? mode = EQUAL;? break;? }

Czasami wpisanie argumentów w niepoprawnej kolejno�ci powoduje b�d, którego nie mo�nawykry� przez mechanizm sprawdzania typów, np.:

? memset(p, n, 0); /* Zapisuje n zer w p */

zamiast

memset(p, 0, n); /* Zapisuje n zer w p */

Czasami co� zostaje zmienione bez wiedzy programisty, np. nie wiemy, �e jaka� proceduramo�e zmienia� pewne globalne lub wspó�u�ytkowane zmienne.

5.4. OSTATNIA DESKA RATUNKU 137

Nieraz u�yty algorytm lub struktura danych zawieraj fatalny b�d, którego po prostu niedostrzegamy. Przygotowujc materia�y do omówienia list powizanych, sporzdzili�my pakietfunkcji s�u�cych do tworzenia nowych elementów listy oraz do�czania ich na pocztku i ko�-cu struktury danych itp. (funkcje te mo�na obejrze� w rozdziale 2.). Oczywi�cie sprawdzili�my,czy wszystko jest w porzdku za pomoc specjalnie napisanego w tym celu programu testowego.Kilka pierwszych testów zosta�o zako�czonych pomy�lnie, ale w pewnym momencie nastpi�aefektowna awaria. Oto kod �ród�owy tamtego programu:

? while (scanf("%s %d", name, &value) != EOF) {? p = newitem(name, value);? list1 = addfront(list1, p);7 list2 = addend(list2, p);? }? for (p = list1; p != NULL; p = p->next)? printf("%s %d\n", p->name, p->value);

A� trudno uwierzy�, ile k�opotów sprawi�o nam dostrze�enie, �e pierwsza p�tla umieszcza�aten sam w�ze� p w obu listach, przez co gdy przyst�powali�my do drukowania, wska�niki by�ybeznadziejnie pomieszane.

Takie b��dy s trudne do wykrycia, poniewa� pod�wiadomie widzimy to, co chcieliby�mywidzie�. Dlatego w takich przypadkach pomocny jest program diagnostyczny, który zmuszanas do zastanowienia si� nad innymi mo�liwo�ciami i prze�ledzenia rzeczywistego dzia�aniaprogramu zamiast my�lenia o tym, co on powinien robi�. Czasami problem wynika z b��duw ogólnej strukturze programu. Aby wykry� co� takiego, trzeba ponownie przejrze� swoje wst�p-ne za�o�enia.

Zauwa�my przy okazji, �e w przyk�adzie dotyczcym list b�d znajdowa� si� w kodzie te-stujcym, co znacznie utrudnia�o jego znalezienie. To straszne, jak �atwo mo�na zmarnowa�czas na poszukiwaniu b��dów, których nie ma, bo problem tkwi w programie testujcym, albona testowaniu niew�a�ciwej wersji programu tudzie� poniewa� zaniedba�o si� aktualizacj� bd�kompilacj� programu przed wznowieniem testowania.

Je�li mimo znacznego wysi�ku nie uda Ci si� znale�� b��du, to zrób sobie przerw�. Odpoczniji chwilowo zajmij si� czym� innym. Porozmawiaj z koleg i popro� go o pomoc. Rozwizaniemo�e pojawi� si� nagle, nie wiadomo skd, a nawet je�li nie, po powrocie do pracy nie b�dzieszju� tkwi� w tym samym zau�ku.

Zdarza si� te�, cho� niezwykle rzadko, �e �ród�em problemów jest kompilator, biblioteka,system operacyjny, a nawet sprz�t. Mo�na to podejrzewa� zw�aszcza wówczas, gdy b�d wyst-pi� bezpo�rednio po wprowadzeniu zmian w �rodowisku. Nigdy nie nale�y rozpoczyna� szuka-nia b��dów od tych miejsc, ale po wykluczeniu wszystkich innych mo�liwo�ci to mo�e by�ostatnie, co nam zostanie. Kiedy� przenosili�my du�y program do formatowania tekstu z sys-temu Unix do komputera PC. Kompilacja zako�czy�a si� bez �adnych problemów, ale programdzia�a� bardzo dziwnie: opuszcza� mniej wi�cej co drugi znak w danych wej�ciowych. Pierwsznasz my�l by�o to, �e ma to jaki� zwizek z u�ywaniem 16-bitowych liczb ca�kowitych za-miast 32-bitowych albo z kolejno�ci bajtów. Jednak po wydrukowaniu znaków, tak jak by�y przed-stawiane p�tli g�ównej, odkryli�my, �e b�d tkwi� w standardowym pliku nag�ówka ctype.hdostarczanym przez producenta kompilatora. Zawiera� on implementacj� funkcji isprintw postaci makra funkcyjnego:

? #define isprint(c) ((c) >= 040 && (c) < 0177)

a g�ówna p�tla pobierania danych by�a zdefiniowana nast�pujco:

138 5. USUWANIE B�DÓW

? while (isprint(c = getchar()))? ...

Za ka�dym razem, gdy na wej�ciu pojawia�a si� spacja (o warto�ci ósemkowej 40, któr sto-suje si� w z�ym stylu zamiast zapisu ' ') lub znak o wy�szym numerze, funkcja getchar by�awywo�ywana po raz drugi, poniewa� makro ewaluowa�o swój argument dwa razy, przy czympierwszy znak znika� bezpowrotnie. Nasz kod �ród�owy mo�e nie by� szczytem elegancji —warunek p�tli móg�by by� prostszy — ale plik nag�ówkowy od dostawcy kompilatora bez naj-mniejszych wtpliwo�ci zawiera� b�d.

Przyk�ady tego b��du mo�na spotka� do dzi�. Poni�sze makro pochodzi z wci� u�ywanychplików nag�ówkowych innego producenta:

? #define __iscsym(c) (isalnum(c) || ((c) == '_'))

Obfitym �ród�em b��dów powodujcych nienormalne dzia�anie programów s wycieki pami�ci,tzn. przypadki nieodzyskania nieu�ywanych ju� fragmentów pami�ci. Kolejnym jest niezamy-kanie plików, które prowadzi do zape�nienia tablicy plików otwartych, przez co nie mo�naotwiera� nast�pnych. Awarie programów zawierajcych wycieki pami�ci cz�sto wygldaj bar-dzo tajemniczo. Poniewa� do usterki dochodzi po wyczerpaniu pewnych zasobów, nie da si�odtworzy� specyficznych zdarze�.

Z rzadka k�opoty sprawia sprz�t. W procesorze Pentium z 1994 roku wyst�powa� b�d, któ-ry powodowa�, �e niektóre obliczenia na liczbach zmiennoprzecinkowych dawa�y z�e wyniki.Ta szeroko nag�o�niona usterka w projekcie urzdzenia du�o firm� kosztowa�a, ale gdy ju� jzidentyfikowano, b�d da�o si� powtarza�. Jeden z najdziwniejszych b��dów, jakie widzieli�myw swojej karierze, znajdowa� si� w starym programie kalkulatora dzia�ajcym w systemie dwu-procesorowym. Czasami dla wyra�enia 0/5 zwraca� warto�� 0.5, a niekiedy drukowa� jak� in-n warto��, typu 0.7432, cho� trzeba przyzna�, �e jak ju� to robi�, to konsekwentnie. Nie da�osi� w �aden sposób przewidzie�, czy w danym przypadku wynik b�dzie poprawny, czy nie.W ko�cu odkryto, i� �ród�em problemu jest usterka w jednostce odpowiedzialnej za obliczeniazmiennoprzecinkowe w jednym z procesorów. Poniewa� do wykonywania kalkulatora by� lo-sowo wybierany albo jeden, albo drugi procesor, raz wyniki by�y poprawne, a innym razemniedorzeczne.

Wiele lat temu u�ywali�my maszyny, której wewn�trzn temperatur� mo�na by�o oszacowa� napodstawie liczby niepoprawnych bitów niskich w obliczeniach zmiennoprzecinkowych. Oblu-zowa�a si� jedna z kart uk�adu elektronicznego i w miar� jak ros�a temperatura, karta ta od-chyla�a si� coraz bardziej, co powodowa�o, �e wi�cej bitów zostawa�o odci�tych od p�yty mon-ta�owej.

5.5. B��dy niepowtarzalneNajtrudniejsze do wytropienia s te b��dy, które pojawiaj si� nieregularnie — najcz��ciejprzyczyn ich powstawania nie jest banalne uszkodzenie sprz�tu. Jednak cenn wskazówk jestju� sam fakt, �e tak si� zachowuj. Mo�na dedukowa�, �e prawdopodobn przyczyn b��du jestnie usterka w algorytmie, lecz raczej to, i� program korzysta z danych, które za ka�dym razems inne.

Sprawd�, czy wszystkie zmienne s zainicjalizowane. Mo�liwe, �e która� z nich otrzymujelosow warto�� odpowiadajc temu, co by�o ostatnio zapisane w przypisywanym jej obszarze

5.5. B�DY NIEPOWTARZALNE 139

pami�ci. W j�zykach C i C++ najcz�stszymi sprawcami s zmienne lokalne funkcji i pami��uzyskiwana za pomoc funkcji alokujcych. Wszystkim zmiennym przypisz konkretne warto-�ci. Je�li w programie u�ywana jest warto�� pocztkowa generatora liczb losowych, której cz�-sto nadaje si� warto�� na podstawie aktualnej daty, to przypisz jej jak� sta� warto��, np. 0.

Je�eli dodanie kodu diagnostycznego powoduje zmian� zachowania lub wr�cz znikni�cieb��du, to mo�na podejrzewa� nieprawid�owo�� przy alokacji pami�ci — jaka� instrukcja zapi-suje dane poza przydzielonym obszarem i dodanie kodu diagnostycznego wprowadza modyfi-kacj� rozmieszczenia elementów w pami�ci, której skutkiem jest zmiana efektu wywo�ywanegoprzez b�d. Wi�kszo�� funkcji wyj�ciowych, od printf po funkcje okien dialogowych, alokujepami�� samodzielnie, co dodatkowo zaciemnia obraz.

Je�li miejsce awarii wydaje si� odleg�e od wszystkiego, co mog�oby by� zepsute, to najbar-dziej prawdopodobn przyczyn problemu jest b��dne zmienienie zawarto�ci obszaru pami�ciw miejscu, które jest u�ywane dopiero pó�niej. Czasami problem dotyczy tzw. wiszcegowska�nika, czyli omy�kowego zwrócenia przez funkcj� wska�nika na zmienn lokaln i pó�-niejszego jego u�ycia. �rodkiem profilaktycznym przed tak odroczon katastrof jest zwróce-nie adresu zmiennej lokalnej:

? char *msg(int n, char *s)? {? char buf[100];?? sprintf (buf, "B�d %d: %s\n", n, s);? return buf;? }

Zanim wska�nik zwrócony przez funkcj� msg zostanie u�yty, b�dzie ju� wskazywa� nic nie-znaczce miejsce w pami�ci. Musisz przydzieli� pami�� za pomoc funkcji malloc, u�y� sta-tycznej tablicy albo za�da�, aby wywo�ujcy dostarczy� pami��.

U�ycie dynamicznie alokowanej warto�ci ju� po jej zwolnieniu objawia si� w podobny spo-sób. Wspominali�my o tym w rozdziale 2., przy okazji omawiania funkcji freeall. Poni�szykod zawiera b�d:

? for (p = listp; p != NULL; p = p->next)? free (p);

Pami�ci, która zosta�a zwolniona, nie wolno u�ywa�, poniewa� jej zawarto�� mog�a si�zmieni� i nie ma pewno�ci, �e instrukcja p->next wci� wskazuje w�a�ciwe miejsce w pami�ci.

W niektórych implementacjach funkcji malloc i free dwukrotne zwolnienie elementu po-woduje uszkodzenie wewn�trznych struktur danych, ale nie wywo�uje to �adnych k�opotówprzez d�u�szy czas, dopóki kolejne wywo�anie nie wywróci si� na tym ba�aganie. Pewne funkcjealokacyjne maj opcje diagnostyczne, za pomoc których mo�na sprawdzi� spójno�� pola dzia-�a� przed ka�dym wywo�aniem. W�cz je, je�li próbujesz wytropi� nieregularnie zachowujcysi� b�d. Je�eli w ten sposób nic nie wskórasz, mo�esz napisa� w�asn funkcj� alokujc, któramog�aby sprawdza� niespójno�� swoich w�asnych zachowa� albo zapisywa� w dziennikuwszystkie wywo�ania, aby mo�na je by�o pó�niej przeanalizowa�. Napisanie funkcji alokujcejpami��, gdy nie zale�y nam bardzo na szybko�ci dzia�ania, jest �atwe, a wi�c strategi� t� mo�nawykona�, je�eli problem jest powa�ny. Istniej te� �wietne komercyjne narz�dzia s�u�ce dosprawdzania zarzdzania pami�ci oraz wykrywajce b��dy i wycieki pami�ci. Je�li nie masz donich dost�pu, mo�esz wykorzysta� niektóre z ich zalet, piszc w�asne funkcje malloc i free.

140 5. USUWANIE B�DÓW

Je�eli jedna osoba nie ma problemów z programem, a inna ma, to znaczy, �e istnieje jaka�usterka, która ujawnia si� tylko w okre�lonych warunkach. Odpowiedzialne za to mog by�jakie� pliki wczytane przez program, prawa dost�pu do plików, zmienne �rodowiskowe, �cie�kidost�pu polece�, ustawienia domy�lne lub pliki u�ywane podczas uruchamiania programu. Trudnocokolwiek w takich sytuacjach doradzi�, poniewa� aby odtworzy� �rodowisko, w którym programzawodzi, trzeba by� t drug osob.

wiczenie 5.1. Napisz w�asne wersje funkcji malloc i free, których b�dzie mo�na u�y� dorozwizywania problemów z zarzdzaniem pami�ci. Jednym z rozwiza� mo�e by� sprawdza-nie w ka�dym wywo�aniu ca�ej przestrzeni roboczej. Odmiennym podej�ciem jest zapisywaniedanych diagnostycznych w dzienniku, aby mog�y zosta� przetworzone przez inny program.Bez wzgl�du na to, któr metod� wybierzesz, na pocztku i ko�cu ka�dego alokowanego blokudodaj znaczniki, by ujawni� ewentualne przypadki przekroczenia zakresu z obu stron.

5.6. Narz�dzia diagnostyczneW znajdowaniu b��dów pomocne s nie tylko programy diagnostyczne. Istnieje wiele innychnarz�dzi, które mog nam pomóc dotrze� do wa�nych informacji w wielkich zbiorach danych,znale�� anomalie lub tak zmieni� uk�ad danych, aby �atwiej mo�na by�o zobaczy�, co si� dzieje.Wiele z nich znajduje si� w standardowym wyposa�eniu warsztatu. Niektóre zosta�y napisanew celu znalezienia konkretnego b��du lub przeanalizowania specyficznego problemu.

W tym podrozdziale omówimy prosty program o nazwie strings, który jest szczególniepomocny w przegldaniu plików sk�adajcych si� g�ównie ze znaków niedrukowalnych, a wi�cnp. plików wykonywalnych i tajemniczych formatów binarnych u�ywanych przez niektóreedytory tekstu. We wn�trzu cz�sto kryj si� ró�ne cenne informacje, takie jak tekst dokumen-tu, komunikaty o b��dach i nieudokumentowanych opcjach, nazwy plików i katalogów, a tak�enazwy funkcji, które mog�y by� wywo�ane przez program.

Programu strings u�ywamy równie� do znajdowania tekstu w innych plikach binarnych.Wiele plików graficznych zawiera znaki ASCII opisujce program, w którym zosta�y utworzone,a pliki skompresowane i archiwa (np. ZIP) mog zawiera� nazwy plików. Wszystkie te infor-macje mo�na odkry� za pomoc programu strings.

W systemach uniksowych istnieje ju� implementacja programu strings, chocia� nieco innaod tej, któr przedstawimy tutaj. Rozpoznaje ona programy na wej�ciu i bada tylko tekst i seg-menty danych, ignorujc tablic� symboli. Za pomoc opcji -a mo�na j zmusi� do zbadaniaca�ego pliku.

Program strings pobiera tekst ASCII z plików binarnych, tak �e mo�na go pó�niej wczy-ta� lub przetworzy� przez inne programy. Je�li znaleziony komunikat o b��dzie nie ma �adnegoidentyfikatora, to mo�e by� trudno odgadn�, jaki program go zg�osi�, nie mówic ju�, dlacze-go to zrobi�. Wówczas mo�e pomóc przeszukanie podejrzanych katalogów przy u�yciu polece-nia zbli�onego do zapisanego ni�ej:

% strings *.exe *.dll | grep 'Tajemniczy komunikat'

Funkcja strings wczytuje plik i drukuje wszystkie �a�cuchy sk�adajce si� przynajmniejz MINLEN = 6 drukowalnych znaków.

5.6. NARZDZIA DIAGNOSTYCZNE 141

/* strings: pobiera znaki drukowalne ze strumienia */void strings(char *name, FILE *fin){ int c, i; char buf[BUFSIZ];

do { /* Jeden raz dla kadego �a�cucha */ for (i = 0; (c = getc(fin)) != EOF; ) { if (!isprint(c)) break; buf[i++] = c; if (i >= BUFSIZ) break; } if (i >= MINLEN) /* Drukuje, je�li �a�cuch jest wystarczaj�co d�ugi */ printf("%s:%.*s\n", name, i, buf); } while (c != EOF);}

�a�cuch formatu %.*s u�yty w wywo�aniu funkcji printf pobiera d�ugo�� �a�cucha z na-st�pnego argumentu (i), poniewa� �a�cuch (buf) nie jest zako�czony zerem.

P�tla do-while znajduje i drukuje ka�dy �a�cuch, a dzia�anie ko�czy, gdy napotka znakko�ca pliku. Dzi�ki temu, �e na ko�cu funkcji znajduje si� sprawdzenie ko�ca pliku, funkcjagetc oraz p�tle �a�cuchowe mog mie� wspólny warunek zako�czenia i jedno wywo�anie funkcjiprintf mo�e obs�ugiwa� koniec �a�cucha, koniec pliku oraz zbyt d�ugie �a�cuchy.

W standardowej p�tli zewn�trznej ze sprawdzeniem warunku na pocztku lub pojedynczejp�tli z funkcj getc i bardziej skomplikowanym kodem �ród�owym konieczne by by�o dwu-krotne wywo�anie funkcji printf. Takie rozwizanie zastosowali�my na pocztku, ale zrobili�myb�d w instrukcji wywo�ujcej funkcj� printf. Poprawili�my go w jednym miejscu, lecz zapo-mnieli�my o jeszcze dwóch innych („Czy pope�ni�em ten sam b�d jeszcze gdzie� indziej?”).Wówczas sta�o si� jasne, �e program trzeba napisa� ponownie, aby by�o w nim mniej powtó-rze� kodu. Tak doszli�my do p�tli do-while.

Funkcja main programu strings wywo�uje funkcj� strings dla ka�dego pliku przekazanegojej jako argument:

/* main: znajduje znaki drukowalne w plikach */int main(int argc, char *argv[]){ int i; FILE *fin;

setprogname("strings"); if (argc == 1) eprintf("Sposób u�ycia: nazwy plików"); else { for (i = 1; i < argc; i++) { if ((fin = fopen(argv[i], "rb")) == NULL) weprintf("Nie mo�na otworzy� pliku %s:", argv[i]); else { strings(argv[i], fin); fclose(fin); } }

142 5. USUWANIE B�DÓW

} return 0;}

Mo�e si� dziwisz, �e funkcja strings nie pobiera danych ze swojego standardowego stru-mienia wej�ciowego, gdy nie zostan podane �adne pliki. Pocztkowo to robi�a. Aby wyja�ni�,dlaczego teraz tego nie robi, musimy opowiedzie� histori� pewnego b��du.

Oczywistym testem, za pomoc którego mo�na sprawdzi� program strings, jest urucho-mienie go na nim samym. Program dzia�a� prawid�owo w systemie Unix, ale w systemie Win-dows 95 polecenie

C:\> strings <strings.exe

zwróci�o dok�adnie pi�� wierszy danych:

!This program cannot be run in DOS mode'[email protected]

Pierwszy wiersz wyglda jak komunikat o b��dzie, przez co zmarnowali�my troch� czasu nadowiedzenie si�, �e jest to �a�cuch zapisany w programie, a dane wyj�ciowe s poprawne, przy-najmniej jak na razie. Czasami zdarza si�, i� sesja diagnostyczna zostaje przerwana z powoduniezrozumienia �ród�a pochodzenia komunikatu.

Ale danych wyj�ciowych powinno by� wi�cej, wi�c gdzie si� podzia�y? Wreszcie której� no-cy o�wieci�o mnie („Gdzie� ju� to widzia�em!”). Jest to problem z przeno�no�ci, o którym sze-rzej piszemy w rozdziale 8. Pierwsza wersja programu wczytywa�a dane tylko ze standardowegowej�cia i u�ywa�a do tego celu funkcji getchar. Ale w systemie Windows funkcja ta zwracaznak ko�ca pliku, je�li w danych tekstowych napotka konkretny bajt (0x1A, czyli znak Ctrl+Z).To powodowa�o przedwczesne ko�czenie pracy programu.

Jest to ca�kowicie poprawne zachowanie, ale nie tego oczekiwali�my, biorc pod uwag� na-sze do�wiadczenia z u�ywania programu w systemie Unix. Rozwizaniem jest otwarcie plikuw trybie binarnym przy u�yciu trybu „rb”. Ale strumie� stdin jest ju� otwarty i nie da si�zmieni� jego trybu w �aden standardowy sposób (mo�na by by�o u�y� funkcji takich jak fdopeni setmode, ale nie nale� one do standardu j�zyka C).W efekcie stajemy przed wyborem jednejz kilku nieprzyjemnych mo�liwo�ci: zmusi� u�ytkownika do podania nazwy pliku, dzi�ki czemuprogram b�dzie dobrze dzia�a� w systemie Windows, cho� jest to nietypowe rozwizanie dlasystemu Unix; po cichu tworzy� niepoprawne odpowiedzi, gdy u�ytkownik systemu Windowsusi�uje wczyta� dane ze standardowego wej�cia; albo zastosowa� kompilacj� warunkow, bydostosowa� zachowanie programu do ró�nych systemów, co zmniejsza jego przeno�no��. Zde-cydowali�my si� na pierwsz z wymienionych mo�liwo�ci, poniewa� dzi�ki temu programwsz�dzie b�dzie dzia�a� tak samo.

wiczenie 5.2. Program strings drukuje �a�cuchy zawierajce przynajmniej MINLEN znaków,co czasami powoduje zwrócenie wi�kszej ilo�ci danych, ni� potrzeba. Zmodyfikuj programstrings tak, aby przyjmowa� opcjonalny argument s�u�cy do okre�lania minimalnej d�ugo�ci�a�cucha.

5.7. B�DY POPE�NIONE PRZEZ INNYCH 143

wiczenie 5.3. Napisz funkcj� vis kopiujc dane wej�ciowe na wyj�cie i zamieniajc bajtyniedrukowalne, takie jak znak Backspace, znaki sterujce i znaki nienale�ce do zestawu ASCIIna symbole w formacie \Xhh, przy czym hh oznacza szesnastkow reprezentacj� danego znaku.W przeciwie�stwie do strings funkcja vis jest najbardziej przydatna przy analizowaniu da-nych zawierajcych niewielk liczb� znaków niedrukowalnych.

wiczenie 5.4. Jaki wynik zwróci funkcja vis, je�li na wej�ciu otrzyma �a�cuch \X0A? Como�na zrobi�, aby funkcja vis zwraca�a niedwuznaczne wyniki?

wiczenie 5.5. Rozszerz zakres dzia�ania funkcji, tak aby przetwarza�a sekwencje plików, �ama�ad�ugie wiersze w dowolnym miejscu i usuwa�a wszystkie niedrukowalne znaki. Jakie jeszcze innezadania zgodne z przeznaczeniem programu mog�aby spe�nia� ta funkcja?

5.7. B��dy pope�nione przez innychNiewielu programistów ma przyjemno�� tworzy� nowy system od podstaw. Znacznie cz��cieju�ywaj, modyfikuj, a wi�c i poprawiaj, kod napisany przez innych programistów.

Wszystko, co napisali�my do tej pory na temat znajdowania i eliminowania b��dów, ma za-stosowanie tak�e do b��dów pope�nionych przez kogo� innego. Przed przystpieniem do pracykonieczne jest jednak zbadanie organizacji programu oraz zrozumienie sposobu my�lenia i pracypoprzednika. W pewnym bardzo du�ym projekcie programistycznym u�yto okre�lenia „odkry-cie”, stanowicego ca�kiem dobr przeno�ni�. Zadanie polega na odkryciu, o co chodzi w ko-dzie, którego my nie napisali�my.

W takich przypadkach bardzo pomocne s ró�ne narz�dzia. U�ywajc programów do prze-szukiwania tekstu, takich jak grep, mo�na znale�� wszystkie wystpienia wybranej nazwy. Ge-neratory odsy�aczy:g (ang. cross-referencer) pozwalaj zapozna� si� ze struktur programu. Wy-kres przedstawiajcy wywo�ania funkcji jest pomocny, je�li nie jest zbyt du�y. Wykonywaniekodu po jednej instrukcji za pomoc programu diagnostycznego pozwala odkry� kolejno�� zda-rze�. Zagldajc do historii wersji programu, mo�na dowiedzie� si�, jak program rozwija� si� wczasie. Cz�ste zmiany oznaczaj, �e kod jest s�abo zrozumiany albo podlega zmieniajcym si�wymaganiom, a wi�c mo�e stanowi� potencjalne �ród�o b��dów.

Czasami musisz szuka� b��dów w oprogramowaniu, za które nie odpowiadasz i którego kod�ród�owy nie jest dost�pny. W takich przypadkach musisz zidentyfikowa� i scharakteryzowa�b�d na tyle dobrze, aby móc go precyzyjnie omówi� w raporcie i przy okazji opracowa� jakie�dobre „obej�cie” pozwalajce go wyeliminowa�.

Kiedy wyda Ci si�, �e znalaz�e� b�d w nie swoim programie, przede wszystkim upewnij si�,i� to na pewno jest b�d, aby nie marnowa� czasu autora i nie narazi� si� na utrat� reputacji.

Gdy znajdziesz b�d w kompilatorze, równie� upewnij si�, �e to rzeczywi�cie b�d kompila-tora, a nie Twojego programu. Przyk�adowo w j�zykach Ci C++ nie okre�lono, czy operacjabitowego przesuni�cia w prawo powinna wstawia� bity zerowe (przesuni�cie logiczne), czy po-wiela� bit znaku (przesuni�cie arytmetyczne). Z tego powodu niektórzy pocztkujcy progra-mi�ci my�l, �e konstrukcje typu

? i = -1;? printf ("%d\n", i >> 1);

144 5. USUWANIE B�DÓW

s b��dne, je�li nie zwróc oczekiwanego wyniku. Jest to jednak kwestia przeno�no�ci, gdy�powy�szy kod mo�e ró�nie si� zachowywa� w rozmaitych systemach i nie b�dzie to oznacza�ob��du. Sprawd� swój test w ró�nych systemach i upewnij si�, �e dobrze rozumiesz, co si� dzieje.Najlepiej skontroluj te� definicj� j�zyka.

Sprawd�, czy b�d nie jest znany. Czy masz najnowsz wersj� programu? Czy istnieje listapoprawionych b��dów? Wi�kszo�� programów jest wydawana w wielu ró�nych wersjach. Je�liznajdziesz usterk� w wersji 4.0b1, to wcale nie musi jej by� w wersji 4.04b2 albo mo�e w jejmiejsce powsta� nowa. W ka�dym razie niewielu programistów pasjonuje si� poprawianiemb��dów w starszych wersjach programów.

Wreszcie postaw si� w roli osoby, która otrzyma Twój raport. Na pewno chcesz dostarczy�w�a�cicielowi programu jak najlepszy przypadek testowy. Nie b�dziesz zbyt pomocny, je�lib�d uda Ci si� ujawni� tylko przy du�ych ilo�ciach danych wej�ciowych, w wyszukanym �ro-dowisku albo przy zastosowaniu wielu plików pomocniczych. Postaraj si� ograniczy� test dojak najmniejszego samodzielnego pakietu. Do�cz wszystkie mogce si� przyda� informacje,takie jak wersja programu, rodzaj u�ytego kompilatora, system operacyjny czy opis sprz�tu.Dla b��dnej wersji funkcji isprint z podrozdzia�u 5.4 mogliby�my dostarczy� poni�szy pro-gram testowy:

/* Program testowy ujawniaj�cy b��d w funkcji isprint */int main(void){ int c; while (isprint(c = getchar()) || c != EOF) printf ("%c", c); return 0;}

Jako przypadek testowy mo�e pos�u�y� dowolny wiersz tekstu zawierajcy drukowalne znaki,poniewa� na wyj�ciu pojawi si� tylko po�owa danych wej�ciowych:

% echo 1234567890 | isprint_test24680%

Najlepsze powiadomienia o b��dach to takie, które do zademonstrowania b��du wymagaju�ycia jednego lub najwy�ej dwóch wierszy danych wej�ciowych w �wie�ym systemie i zawie-raj rozwizanie. Wysy�aj takie powiadomienia o b��dach, jakie sam chcia�by� otrzymywa�.

5.8. PodsumowaniePrzy odrobinie dobrych ch�ci usuwanie b��dów mo�e by� dobr rozrywk, jak rozwizywanie�amig�ówek. Jednak bez wzgl�du na to, czy nam si� to podoba, czy nie, sztuk� t� b�dziemyuprawia� cz�sto i regularnie. Poniewa� fajnie by by�o, gdyby b��dy nie istnia�y, staramy si� pi-sa� jak najlepszy kod od samego pocztku. W dobrze napisanym kodzie nie tylko jest mniejb��dów, lecz tak�e �atwiej je znale��, je�li ju� si� pojawi.

Po zauwa�eniu b��du w programie nale�y najpierw zastanowi� si�, co mo�na wywniosko-wa� z jego cech szczególnych. Skd móg� si� wzi�? Czy wyglda znajomo? Czy zmieni�o si�co� w programie? Czy w danych, które spowodowa�y jego wystpienie, jest co� szczególnego?Czasami wystarczy kilka dobrze dobranych przypadków testowych i kilka instrukcji drukujcych.

LEKTURA UZUPE�NIAJ�CA 145

Je�li nie ma �adnych tropów, to i tak najlepiej jest zacz� od dok�adnego przemy�leniasprawy i próby zaw��enia liczby podejrzanych miejsc. Jedn z mo�liwo�ci jest stopniowe ogra-niczanie zbioru danych wej�ciowych, aby uzyska� niewielki zestaw powodujcy awari�. Innmo�liwo�ci jest usuwanie po kolei fragmentów kodu �ród�owego, które nie powinny mie�z tym nic wspólnego. Mo�na do programu doda� kod sprawdzajcy, który w�cza si� dopieropo wykonaniu przez program okre�lonej liczby dzia�a�. Wszystkie wymienione techniki toelementy ogólnej strategii „dziel i rzd�”, która równie dobrze sprawdza si� zarówno w diagno-zowaniu programów, jak i w polityce i dzia�aniach wojennych.

Korzystaj tak�e z innych pomocy. Niezwykle przydatne bywa obja�nienie dzia�aniakodu komu� innemu (cho�by pluszowemu misiowi). Pos�u� si� programem diagnostycznymdo sprawdzenia zawarto�ci stosu wywo�a�. U�yj którego� z komercyjnych narz�dzi do wykry-wania wycieków pami�ci, przypadków naruszenia granic tablic, podejrzanego kodu itp. Z mo�liwo-�ci wykonywania kodu po jednej instrukcji skorzystaj wówczas, gdy stanie si� jasne, �e �le ro-zumiesz, jak dzia�a kod.

Poznaj siebie i rodzaje b��dów, które pope�niasz. Kiedy znajdziesz i usuniesz jaki� b�d,sprawd�, czy w innych miejscach programu nie ma jeszcze podobnych usterek. Zastanów si�,co si� sta�o, aby móc w przysz�o�ci unikn� powtórzenia tej sytuacji.

Lektura uzupe�niajcaMnóstwo cennych informacji na temat usuwania b��dów mo�na znale�� w ksi�kach Steve’aMaguire’a Writing Solid Code (Microsoft Press, 1993) i Steve’a McConella Kod doskona�y(Helion, 2010).

Skorowidz

Kobieta: Czy jest tu moja ciotka Minnie?

Driftwood: Có�, mo�esz wej�� i poszuka�, je�eli chcesz.Je�li jej tu nie ma, to zapewne mo�esz znale� kogo� równie dobrego.

Bracia Marx, Noc w operze

#define, 31#ifdef, 207%f, 128%lf, 128&, 17.length, 32?, 12, 18|, 17++, 19, 22+=, 109<=, 24==, 170, 31

Aabstrakcja, 112, 208addfront, 55aktualizacja komentarza, 35algorytm, 8, 193

czas dzia�ania, 50dane wej�ciowe, 44jasny, 86Markowa, 70, 72, 79, 90

test, 168podstawowy, 39, 83porównywanie czasu dzia�ania, 50przeszukiwania,

binarnego, 41sekwencyjnego, 40

przyspieszanie, 181rola, 39sortowania, 42, 47tworzenia,

�a�cuchów elementów, 166tekstu, 85

usuwania nieu�ytków, 116wybór, 68, 182wymagania pami�ciowe, 50wyszukiwania binarnego, 42zako�czenie, 77z�o�ono��,

oczekiwana, 50pesymistyczna, 50

alokacja, 116pami�ci, 24, 166, 186, 192

analizaprojektu, 8sk�adniowa drzewa, 63

ANSI, 202C, 46, 53, 202, 204

standard, 24API, 113, 204application programming interface, 113argumenty makra, 29Ariane 5, 165arytmetyczne

przesuni�cie, 200asembler, 188asercja, 150

260 SKOROWIDZ

asocjacyjnatablica, 86

associative array, 86atexit, 116automatyzacja, 7, 254

testów, 157Awk, 9, 86, 87, 90, 158, 180, 193, 235, 237, 245

Bbackwards compatibility, 215bajty

kolejno��, 201porz�dek, 211

balanced tree, 61B-drzewo, 63Beta wersja, 168bezwzgl�dna

warto��, 49bia�a skrzynka, 167biblioteka, 202big-endian, 218binarne

przeszukiwanie, 46drzewo poszukiwa�, 59, 60

bitowyoperator, 17pole, 201

b��dasercja, 150b��dne przekonanie, 136cechy usterki, 132diagnostyka, 127dodanie instrukcji wy�wietlaj�cych informacje, 132dziennik, 134informacja, 151innych programistów, 143kompilatora, 143komunikat, 118minimalny zestaw danych wej�ciowych, 132na ��danie, 131nieregularny, 138nowy, 129obs�uga, 99, 101, 117po zmianie, 129porównywanie plików, 135powielenie, 129przepe�nienia bufora, 164roku 2000, 188rozmowa z pluszowym misiem, 131rzeczywiste dzia�anie programu, 137sk�adni, 21skutki lekcewa�enia, 130sprz�tu, 138strumie�, 134u jednej osoby, 140

usuwanie, 125, 147uwa�ne przeczytanie kodu, 131wykres, 134wykrywanie, 9wymuszanie powtarzalno�ci, 131zasada obs�ugi, 119znajdowanie, 147znany, 144

boundary condition testing, 148Bourne, 166break, 27Brooks, 69, 95bsearch, 46bucket, 64bufor

b��d przepe�nienia, 164danych,

wej�ciowych, 187wyj�ciowych, 187

rozmiar, 76bug, 125build, 76

CC, 9, 10, 17, 19, 22, 24, 27, 28, 31, 32, 40, 44, 48, 53,

54, 64, 66, 73, 81, 83, 89, 96, 103, 107, 114, 116,121, 134, 139, 160, 177, 182, 184, 188, 189, 191,196, 197, 199, 201, 202, 203, 213, 217, 231, 243wada, 79zaleta, 79

C++, 9, 14, 17, 19, 22, 24, 27, 28, 29, 31, 32, 40, 44,47, 51, 53, 54, 59, 64, 66, 83, 89, 108, 110, 111,113, 115, 116, 134, 139, 160, 163, 177, 182, 184, 188,189, 191, 196, 198, 199, 201, 202, 213, 217, 243

case, 26cel testowania, 167cerr, 134Chain, 80char, 200char **array, 40clock, 177Cohen, 218comma-separated values, 94Comparable, 47const, 31cost model, 191cross-referencer, 143CSV, 94, 95, 96, 108, 112csvgetline, 96ctime, 36, 153ctype, 28cyclic redundancy check, 67cykliczna kontrola nadmiarowa, 67czarna skrzynka, 167

SKOROWIDZ 261

czasdzia�ania algorytmu, 50mierzenie, 172, 177pracy procesora, 178u�ycia procesora, 177wykonywania programu, 177

czytelne formatowanie, 16

Ddane, 64, 155

globalne, 34na wyj�ciu, 155najmniejszy typ, 189oznaczanie ko�ca, 77statyczne, 54struktura, 8, 39, 59szkodliwe, 164typ le dobrany, 128wej�ciowe, 187wybór struktur, 89wyj�ciowe, 187wymiana, 209, 212

Date, 178debugging, 125debugowanie, 126, 256decyzje

wielokierunkowe, 25defensive programming, 122defensywne programowanie, 122, 151definicja,

pakietów, 202pola, 99

dekrementacja, 19deque, 84design patterns, 91deskryptywna

nazwa, 13destruktor, 116diagnostyka

b��dów, 127instrukcji, 127kodu, 9programu, 126, 140

diff, 135Dijkstra, 147d�ugo�� s�ów, 85dobry

interfejs, 112kod, 37technika sortowania, 63zestaw testów, 161

domy�lny rozmiar tablicy, 73do�wiadczenia, 253double, 187

do-while, 23drukowanie elementów listy, 56drzewo, 59

analiza sk�adniowa, 63korze�, 59niezrównowa�one, 61poszukiwa� binarne, 59, 60przegl�danie poprzeczne, 62zrównowa�one, 61

dublowanie elementów, 61dwuznaczno�ci unikanie, 16dzieci w�ze�, 60dzielenie, 59dziennik

b��d, 134

Eefekty uboczne, 19efektywno�� wykorzystania pami�ci, 190elastyczno��, 108element

dost�p swobodny, 59dublowanie, 61grupowanie, 16liczenie, 57o zmiennym rozmiarze, 59powi�zany, 14, 64przesuwanie, 53wstawianie, 59

else, 25, 26else-if, 25, 26Ellis, 89endian, 218endprintf, 117enum, 31EOF, 200estrdup, 118ewaluacja, 19, 29exception, 120

Ffall-through, 26fclose, 151fflush, 134fgets, 24, 148filtr spamu, 176final, 31find, 40Flandren, 194float, 187flush, 134flushcaches, 249fopen, 151for, 22, 23

262 SKOROWIDZ

formatCSV, 94, 95, 96p�tla, 22

formatowanieczytelne, 16wyra�enia, 16

fprintf, 151fragment niejasny, 11fread, 151free, 192funkcja

generuj�ca, 81komentarz, 34logiczna, 14�a�cuchowa, 114mieszaj�ca, 64, 67, 74, 75nazwa, 13, 14sortuj�ca, 44

fwrite, 151

Ggarbage collection, 116generate, 242generator

liczb losowych, 49odsy�aczy, 143tekstu, 77

getchar, 23, 28gets, 24, 164getTime, 178GIF, 190globalne

dane, 34optymalizator, 182zmiennne, 112

g�owa, 54g�ówny nurt j�zyka, 197gor�cy punkt, 178, 184, 186graficzne operacje, 188gramatyka, 238granice tabeli, 166grep, 143, 172, 229, 234grupowanie elementów, 16

HHashtable, 79, 83head, 54hermetyzacja, 112hierarchiczna struktura danych, 59Hoare, 42, 47

IIBM 7094, 248idealny komentarz, 33idiom, 22, 24idiomatyczny kod, 36if, 20, 21, 25if...else, 19, 25implementacja,

niezale�ne wyniki, 156programu, 8

indeksowania operator, 85indexOf, 40Inferno, 187informacja

o b��dzie, 151ukrywanie, 99, 100, 112

inicjalizacja, 114statyczna, 115tablica, 167zmienna, 167

inkrementacja, 16, 19in-order traversal, 62insert, 62instrukcja, 16

diagnostyczna, 127sprawdzaj�ca, 26

Integer, 48interaktywnego programu test, 168interfejs, 8, 47, 96, 99, 112, 208, 254, 256

CSV, 112do tablic rozproszonych, 64dobry, 112du�y, 113�atwy w u�yciu, 123poprawny, 150programistyczny, 113publiczny, 80, 108u�ytkownika, 9, 121zasady tworzenia, 112zwi�z�y, 113

internacjonalizacja, 216internationalization, 216internetowy robak, 165interpreter, 237

polece�, 234isspam, 179isupper, 28

Jjasny algorytm, 86Java, 9, 14, 17, 22, 24, 27, 28, 31, 40, 47, 48, 51, 54,

58, 64, 79, 83, 89, 113, 115, 116, 121, 134, 178,188, 199, 213

Java Virtual Machine, 242jednokierunkowa lista, 54

SKOROWIDZ 263

jednolito��, 123j�zyk

ma�y, 222niskiego poziomu, 9, 188nurt g�ówny, 197programowania, 9skryptowy, 236standard, 196wybór, 221wysokiego poziomu, 9

JIT, 247just in time compilation, 247JVM, 242

Kklamry, 27klarowno��, 26, 253klasa, 201

globalna, 13kontenerowa, 79

klucze, 64Knuth, 167, 178, 194kod

diagnostyka, 9dobry, 37generowanie za pomoc� makr, 246idiomatyczny, 36klarowny, 19, 36�atwo�� czytania, 12nizany, 240optymalizacja, 182pokrycie testami, 156przejrzysty, 18regulacja, 183samosprawdzaj�cy, 133spójny, 12sprytny, 18struktura, 16

uwypuklenie, 20testowanie w czasie pisania, 151wolny od b��dów, 147wy�szej jako�ci, 151zale�ny od maszyny, 188zwi�z�y, 19, 86ród�owy, 12

Koenig, 245kolejka, 14

dwukierunkowa, 84kolejno��,

bajtów, 201wykonywania oblicze�, 199

kolizja, 67komentarz, 33, 34

aktualizacja, 35cel stosowania, 37

funkcja, 34idealny, 33niejasny, 37

kompilacjana czas, 247w locie, 247warunkowa, 205

kompilator, 166, 182, 184, 195, 197, 243, 250b��d, 143optymalizacji kodu, 182testowanie, 155, 201

komputer zasady korzystania, 7komunikat, 217

o b��dzie, 118konflikt nazw, 113konstruktor, 115, 116kontener, 83konwencje, 12konwersji wspó�czynnik, 29ko�cowy warunek, 149kopiowanie, 59, 114korze� drzewa, 59kosztów model, 191krotka, 120kube�ek, 64

Llast-in-first-out, 59liczba, 29, 31

0, 31ca�kowita, 45, 191double, 128losowa, 49zmiennoprzecinkowa, 191

liczenie elementów, 57licznik odniesie�, 116LIFO, 59liniowe przeszukiwanie, 40lista, 54, 83

drukowanie elementów, 56jednokierunkowa, 54modyfikacja, 55pami�� wolna, 186tworzenie, 55usuwanie, 57, 58

li��, 61literate programming, 245little languages, 222locality, 186Locanthi, 246logiczne przesuni�cie, 200lokalno�ci zasada, 186lookup, 62losowa liczba, 49

264 SKOROWIDZ

��a�cuch

algorytm tworzenia, 166nazwa, 13Markowa , 70, 79

�a�cuchowa funkcja, 114�atwy w u�yciu interfejs, 123

Mmainstream, 197makro, 28, 31, 32

argumenty, 29generowanie kodu, 246problem, 28

malloc, 24, 129, 192ma�e j�zyki, 222map, 79, 84, 85markov, 70, 91, 163, 170maszyna,

stosowa, 240wirtualna, 237

Math.abs, 49mechanizm wyj�tków, 120memcmp, 179, 183memcopy, 53memcpy, 113memmove, 53, 113, 188memset, 161, 188metacharacters, 228metaznaki, 228Microsoft Visual C++ 5.0, 163mierzenie czasu, 172, 177mieszaj�ca funkcja, 74Mitchell, 89mocy zmniejszenie, 184model,

kosztów, 191statystyczny tekstu, 70

Modula-3, 243modularyzacja, 112

Nnadmiarowa kontrola cykliczna, 67najmniejsze typy danych, 189najprostsza struktura danych, 53najwspanialsze osi�gni�cie informatyki, 64Nameval, 51NaN, 120nawiasy, 16

klamrowe, 20nazwa, 13

deskryptywna, 13elementy powi�zane, 14

funkcja, 14logiczna, 14

klasa globalna, 13konflikt, 113�a�cuch, 13niespójna, 14prywatna, 113sta�a, 13struktura globalna, 13wskanik, 13zmienna,

globalna, 13lokalna, 13p�tlowa, 13

negacja, 35new, 129niedorzeczne warto�ci, 128niejasny

fragment, 11komentarz, 37

niepoprawne dane wej�ciowe, 122nieprzezroczysty typ, 112nies�ychanie du�a warto��, 128niespójna nazwa, 14nietypowe sytuacje, 120niezale�ne implementacje, 156niezamykanie plików, 138niezrównowa�one drzewo, 61niskopoziomowy j�zyk, 9nizany kod, 240not a number, 120notacja, 221, 254

O, 50programowanie, 9

nowy w�ze�, 61null, 32numerycznego programu test, 155nurt g�ówny j�zyka, 197nvcmp, 46

Oobci��eniowe testy, 9obiektu rozmiar, 32Object, 47, 48obliczenia

kolejno�� wykonywania, 199zawczasu, 187

obs�uga b��dów, 99, 101, 117zasada, 119

oczekiwana z�o�ono�� algorytmu, 50odsy�aczy generator, 143odzyskiwanie zasobów, 116ogonowa rekurencja, 62ogólno��, 253

programowania, 7

SKOROWIDZ 265

on the fly compilation, 247O-notation, 50operacja

graficzna, 188wej�cia, 19wyj�cia, 19

operator, 16bitowy, 17indeksowania, 85logiczny, 17priorytet, 17przeci��anie, 189przypisania, 17relacji, 17, 24

opónienia w dostarczaniu poczty, 172optymalizacja, 184, 193

gospodarowania pami�ci�, 189kodu kompilatora, 182wykorzystania zasobów, 9zasada, 171

optymalizator globalny, 182oszcz�dzanie pami�ci, 190oznaczanie ko�ca danych, 77

Ppair, 120pakietów definicja, 202pami��, 114

alokowanie, 24, 166, 186, 192efektywno�� wykorzystania, 190optymalne gospodarowanie, 189oszcz�dzanie, 190podr�czna, 186wolna, 186wyciek, 138zwalnianie, 192

Pathfinder, 130Perl, 9, 86, 87, 90, 237pesymistyczna z�o�ono�� algorytmu, 50p�tla, 16, 21, 22, 23, 24, 148

eliminacja, 185format, 22

pierwsze wyst�pienie znaku, 40pisanie kodu, 151pi�mienne programowanie, 245plik

dziennika, 134nag�ówkowy, 202niezamykanie, 138

poczty opónienia w dostarczaniu, 172podr�czna pami��, 186podstawowe algorytmy, 39, 83pole

bitowe, 201definicja, 99

pomiary, 193wykonywanie, 172

poprawa wydajno�ci, 175poprawno�� interfejsu, 150porównywanie

czasu dzia�ania algorytmów, 50liczb ca�kowitych, 45

portability, 195Portable Operating System Interface, 218porz�dek bajtów, 211POSIX, 204, 218post-order traversal, 63PostScript, 245potok, 249potomek, 60, 61powi�zane elementy, 64pozycja znaku, 29PPM, 190praktyka programowania, 7, 12Prefix, 81, 82pre-order traversal, 63printf, 97, 128, 222priorytetu operator, 17problemu rozmiar, 50procedura przeszukuj�ca, 40procesor, 195prof, 178profil, 172, 173, 178program

diagnostyczny, 126, 140wady, 127zalety, 126

do powszechnego u�ytku, 90generuj�cy tekst, 69graficzny, 155implementacja, 8interaktywny, 168jak napisa�, 12numeryczny, 155odporny na niepoprawne dane wej�ciowe, 122pisze programy, 242profiluj�cy, 172, 173,178prototyp, 98przekazanie do u�ytku, 166przeno�ny, 9, 195przyspieszanie dzia�ania, 183rzeczywiste dzia�anie, 137spowolnienie, 189struktura, 143w�amanie, 164wydajno��, 88, 188z�o�ono�� obliczeniowa, 181

programowaniedefensywne, 122, 151notacja, 9ogólno��, 7

266 SKOROWIDZ

programowaniepi�mienne, 245praktyka, 7, 12prostota, 7przejrzysto��, 7styl, 8, 38zasady, 12

projektu analiza, 8prostota programowania, 7, 253prototyp, 197

programu, 98prywatna nazwa, 113przechowywanie elementów o zmiennym rozmiarze, 59przeci��anie operatorów, 189przegl�danie

poprzeczne, 62wsteczne, 63wzd�u�ne, 63

przejrzysto��, 13programowanie, 7

przekazanie programu do u�ytku, 166przeno�no�� programów, 9, 142, 195, 214, 257przepe�nienie, 46

bufora, 164przesuni�cie

arytmetyczne, 200elementu, 53logiczne, 200

przeszukiwaniebinarne, 41, 46liniowe, 40procedura, 40sekwencyjne, 40tablicy, 154tekstu, 143

przydzielanie pami�ci, 114przypisanie, 16

operator, 17wstawianie do warunku p�tli, 23

przyspieszaniealgorytmu, 181dzia�ania programu, 174, 183struktury danych, 181

publiczny interfejs, 80, 108pu�apki j�zykowe, 198punkt gor�cy, 184, 186putchar, 23

Qqsort, 44, 45, 46queue, 14quicksort, 42, 49

Rrama testowa, 154, 159, 162, 193rand, 49RCS, 135real, 177realloc, 129reduction in strength, 184reentrant, 116reference count, 116referencja, 115regression testing, 157regresywne testowanie, 157, 180, 184regulacja kodu, 183regular expressions, 228regularne wyra�enia, 228rekurencja, 47

ogonowa, 62relacji operator, 17, 24reputacji utrata, 143rgen, 49robak internetowy, 165rozmiar

bufora, 76obiektu, 32problemu, 50tablicy, 29, 33, 66, 104typów danych, 198

rozszerzalna tablica, 51rozwój, 253rzutowanie, 53

Ssamodzielne testy, 158samosprawdzaj�cy si� kod, 133scalanie, 59scanf, 96, 128, 151scmp, 45sekwencyjne wyszukiwanie, 40sentinel, 77shaney, 91sizeof, 32sk�adni b��dy, 21skrócenie czasu usuwania usterek, 125skrypt testowy, 158skryptowy j�zyk, 236s�owa, 73, 85s�ownik, 84, 87

struktura danych, 79sort, 47, 49sortowanie

algorytm, 42, 47dobra technika, 63funkcja, 44szybkie, 42tablic �a�cuchów, 45

SKOROWIDZ 267

spam, 172filtr, 176

specyfikacja, 101zawarto��, 101

split, 103, 105, 109sposoby doboru testów, 154spójno��, 20, 22, 114

kodu, 12zewn�trzna, 114

sprz�tu b��d, 138sta�a, 19, 31

ca�kowitoliczbowa, 31nazwa, 13znakowa, 31

stanu utrzymywanie, 114standard, 197, 202

ANSI C, 24, 202, 222, 225ANSI/ISO j�zyka C, 196ISO j�zyka C++, 196j�zyka, 196

Standard Template Library, 83State, 73statyczna inicjalizacja, 115statyczne dane, 54stderr, 134stdout, 113STL, 59, 83, 90, 120, 163stos, 59, 186

wywo�a�, 126, 130strchr, 40, 179strcmp, 36, 45strcpy, 24strdup, 24StreamTokenizer, 80strerror, 120String, 40, 48strings, 140strlen, 24, 179strncmp, 179stronicowanie, 189strstr, 40, 173, 176, 179strtok, 96, 105, 113struktura

danych, 8, 39, 201najprostsza, 53s�ownik, 79

globalna nazwa, 13kodu, 16programu, 143

strumienie b��dów, 134styl, 12, 255

funkcja, 12programowania, 8, 38

swap, 49Swift, 218swobodny dost�p do elementów, 59

symbole,tablica, 64wieloznaczne, 228

SYS, 177system

zale�no�ci, 208operacyjny, 195

System.err, 134systematyczne testowanie niewielkich przypadków, 154sytuacje nietypowe, 120szkodliwe dane wej�ciowe, 164szybkie sortowanie, 42

Ttabela

granice, 166tablica, 40, 53

asocjacyjna, 86domy�lny rozmiar, 73inicjalizacja, 167�a�cuchów, 45mieszaj�ca, 51, 64, 80

funkcja tworz�ca, 75przeszukanie, 154rozmiar, 29, 33, 66, 104rozproszona, 64rozszerzalna, 51s�owa, 73symboli, 64znaków, 108

tail recursion, 62Tcl/Tk, 9technika usuwania b��dów, 125tekst

algorytm tworzenia, 85generowanie, 77model statystyczny, 70przeszukiwanie, 143

test, 9, 147, 153, 193, 256algorytm Markowa, 168automatyzacja, 157bia�ej skrzynki, 167cel, 167czarnej skrzynki, 167dobry zestaw, 161du�a ilo�ci danych, 163kompilator, 155obci��eniowy, 9pokrycia kodu, 156programu,

graficznego, 155interaktywnego, 168numerycznego, 155

przeci��eniowy, 163rama, 154, 159, 162

268 SKOROWIDZ

testregresywny, 157, 180, 184samodzielny, 158sposoby doboru, 154stopniowy, 153systematyczny, 153testu, 168ustawienia parametrów wej�ciowych, 167w czasie pisania kodu, 151warto�ci brzegowych, 9, 148

rozszerzenie metody, 154wzorcowy, 194zautomatyzowanie, 154zestaw, 153, 167, 174

TEX, 167Thompson, 194, 248threaded code, 240time, 177tuple, 120tworzenie listy, 55typ danych

najmniejszych, 189nieprzezroczysty, 112rozmiar, 198le dobrany, 128

Uuboczne efekty, 19ukrywanie informacji, 99, 100, 112unia, 201Unicode, 216unikanie dwuznaczno��, 16unquote, 96unsigned char, 66ustawianie warto�ci pocz�tkowych, 115usterki czas usuwania, 125usuwanie

b��dów, 147listy, 57, 58usterek, 125

UTF-8, 217utrata reputacji, 143utrzymywanie stanu, 114u�ytkownika interfejs, 9, 121

VVector, 79, 83, 84, 108Visual Basic, 9, 243void*, 44, 53

Wwarto�ci

bezwzgl�dne, 49brzegowych testowanie, 9niedorzeczne, 128nies�ychanie du�e, 128oddzielane przecinkami, 94pocz�tkowych ustawianie, 115zmiennej modyfikacja, 19

wartownik, 77warunek, 25

brzegowy, 148ko�cowy, 149p�tli, 23wst�pny, 149

warunkowa,kompilacja, 205wyra�enie, 19

wci�cia, 16, 20, 21wczytywanie liczb typu double, 128wej�cie, 19wektor, 83weprintf, 61, 117wersja beta, 168w�ze�

dzieci, 60nowy, 61

while, 23, 26wielokierunkowe decyzje, 25wielowej�ciowy program, 116wildcards, 228wisz�cy wskanik, 139w�amanie do programu, 164w�a�ciwo�ci danych wej�ciowych, 155wprintf, 203wskanik

brakuj�cego potomka, 60nazwy, 13wisz�cy, 139

wspó�czynnik konwersji, 29wspó�dzielenie, 114wstawianie elementu, 59wsteczna zgodno��, 215wst�pny warunek, 149wybór

algorytmu, 68, 182j�zyka, 9, 221struktur danych, 89

wycieki pami�ci, 138wydajno��, 171, 257

analiza graficzna, 180poprawa, 175program, 88, 188

wyj�tek, 120wyj�cie, 19

SKOROWIDZ 269

wyk�adnicza z�o�ono�� obliczeniowa, 51wykonywanie pomiarów, 172wykorzystania zasobów optymalizacja, 9wykres b��dów, 134wykrywanie b��dów, 9wymagania pami�ciowe algorytmu, 50wymiana danych, 209, 212wyniki niezale�nych implementacji, 156wyra�enia, 16

formatowanie, 16regularne, 228skomplikowane, 17warunkowe, 19

wysokiego poziomu j�zyk, 9wyszukiwanie

binarne, 42sekwencyjne, 40

wywo�aniestos, 126, 130

wzorzec projektowy, 91

YYorktown, 150, 151

Zzale�no�ci systemowe, 208zarz�dzanie zasobami, 58, 99, 100, 114zasada

korzystania z komputera, 7lokalno�ci, 186obs�ugi b��dów, 119optymalizacji, 171programowania, 12

zasobyodzyskiwanie, 116zarz�dzanie, 58, 99, 100, 114

zautomatyzowanie testowania, 154zbiór, 83

klas kontenerowych, 79zero, 31zestaw

testów, 153, 167, 174znaków, 216

zewn�trzna spójno��, 114zgodno�� wsteczna, 215z�o�ono�� obliczeniowa, 50, 56, 181

wyk�adnicza, 51zmienna, 103

globalna, 13, 112inicjalizacja, 167lokalna, 13modyfikacja warto�ci, 19nazwa, 13p�tlowa, 13wewn�trzna, 103

zmniejszenie mocy, 184znak

pierwsze wyst�pienie, 40pozycja, 29tablica, 108zapytania, 12zestaw, 216

zrównowa�one drzewo, 61zwalnianie pamieci, 114, 192zwi�kszenie wydajno�ci programu, 188zwi�z�o��, 13

kodu, 86