Idź do
• Spis treści
• Przykładowy rozdział
• Skorowidz
Helion SA
ul. Kościuszki 1c
44-100 Gliwice
tel. 32 230 98 63
© Helion 1991–2011
Katalog książek
Twój koszyk
Cennik i informacje
Czytelnia
Kontakt
Lekcja programowania.
Najlepsze praktyki
Autorzy: Brian W. Kernighan, Rob Pike
Tłumaczenie: Łukasz Piwko
ISBN: 978-83-246-3226-8
Tytuł oryginału:
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 treci
Wstp
7
1. Styl
11
1.1. Nazwy
13
1.2. Wyraenia i instrukcje
16
1.3. Spójno i idiomy
20
1.4. Makra w roli funkcji
28
1.5. Liczby magiczne
29
1.6. Komentarze
33
1.7. Dlaczego warto dba o styl?
38
2. Algorytmy i struktury danych
39
2.1. Przeszukiwanie
40
2.2. Sortowanie
42
2.3. Biblioteki
44
2.4. Sortowanie szybkie w Javie
47
2.5. Notacja O
50
2.6. Tablice rozszerzalne
51
2.7. Listy
54
2.8. Drzewa
59
2.9. Tablice mieszania
64
2.10. Podsumowanie
68
3. Projektowanie i implementacja
69
3.1. Algorytm acucha Markowa
70
3.2. Wybór struktury danych
72
3.3. Budowa struktury danych w jzyku C
73
3.4. Generowanie tekstu
77
3.5. Java
79
3.6. C++
83
3.7. Awk i Perl
86
3.8. Wydajno
88
3.9. Wnioski
89
4
SPIS TRECI
4. Interfejsy
93
4.1. Wartoci oddzielane przecinkami
94
4.2. Prototyp biblioteki
95
4.3. Biblioteka dla innych
99
4.4. Implementacja w jzyku C++
108
4.5. Zasady projektowania interfejsów
112
4.6. Zarzdzanie zasobami
114
4.7. Obsuga bdów
117
4.8. Interfejsy uytkownika
121
5. Usuwanie bdów
125
5.1. Programy diagnostyczne
126
5.2. Dobre pomysy, atwe bdy
127
5.3. Brak pomysów, trudne bdy
131
5.4. Ostatnia deska ratunku
135
5.5. Bdy niepowtarzalne
138
5.6. Narzdzia diagnostyczne
140
5.7. Bdy popenione przez innych
143
5.8. Podsumowanie
144
6. Testowanie
147
6.1. Testuj kod podczas jego pisania
148
6.2. Systematyczne testowanie
153
6.3. Automatyzacja testów
157
6.4. Ramy testowe
159
6.5. Testowanie przecieniowe
163
6.6. Porady dotyczce testowania
166
6.7. Kto zajmuje si testowaniem
167
6.8. Testowanie programu markov
168
6.9. Podsumowanie
170
7. Wydajno
171
7.1. Wskie gardo
172
7.2. Mierzenie czasu wykonywania i profilowanie programu
177
7.3. Strategie przyspieszania
181
7.4. Regulowanie kodu
184
7.5. Oszczdzanie pamici
188
7.6. Szacowanie
191
7.7. Podsumowanie
193
8. Przenono
195
8.1. Jzyk
196
8.2. Nagówki i biblioteki
202
8.3. Organizacja programu
204
8.4. Izolacja
208
8.5. Wymiana danych
209
8.6. Kolejno bajtów
210
8.7. Przenono a uaktualnianie
213
8.8. Internacjonalizacja
215
8.9. Podsumowanie
218
SPIS TRECI
5
9. Notacja
221
9.1. Formatowanie danych
222
9.2. Wyraenia regularne
228
9.3. Programowalne narzdzia
234
9.4. Interpretery, kompilatory i maszyny wirtualne
237
9.5. Programy, które pisz programy
242
9.6. Generowanie kodu za pomoc makr
246
9.7. Kompilacja w locie
247
A Epilog
253
B Zebrane zasady
255
Skorowidz
259
5
Usuwanie bdów
bug
b. Usterka lub bd w maszynie, planie itp. poch. USA. 11 marca 1889 Pall Mall Gaz. 1/1: Powiadomiono
mnie, e pan Edison nie pi ju od dwóch dni, próbujc znale usterk (ang. bug) w swoim fonografie
— wyraenie oznaczajce poszukiwanie rozwizania problemu i sugerujce, e gdzie wewntrz ukry
si wyimaginowany insekt, który powoduje trudnoci.
Oxford English Dictionary, wyd. 2.
W poprzednich czterech rozdziaach przedstawilimy sporo przykadów kodu i za kadym razem
udawalimy, e wszystkie one od razu prawidowo dziaay. Oczywicie tak nie byo — w ka-
dym z nich pocztkowo a roio si od bdów. Sowo bug mimo i nie powstao w rodowisku
programistycznym, jest niewtpliwie jednym z najczciej uywanych sów w tej dziedzinie.
Dlaczego tworzenie oprogramowania jest takie trudne?
Jednym z powodów jest to, e na zoono programów ma wpyw liczba interakcji wyst-
pujcych midzy ich skadnikami, a programy s pene skadników i relacji. Istnieje wiele
technik sucych do zmniejszania liczby powiza midzy komponentami. Zalicza si do nich
ukrywanie informacji, abstrakcj i interfejsy oraz waciwoci jzyka, które su do ich reali-
zowania. S równie techniki zapewniajce integralno projektów programów — dowodzenie
poprawnoci programów, modelowanie, analiza wymaga, formalna weryfikacja — ale adna
z nich nie zmienia sposobu, w jaki tworzy si oprogramowanie. Wszystkie okazay si sku-
teczne tylko w rozwizywaniu bardzo maych problemów. Rzeczywisto jest taka, e zawsze
znajd si bdy, które bdziemy wykrywa za pomoc testowania i eliminowa za pomoc
technik usuwania bdów (ang. debugging).
Dobry programista wie, e usuwanie bdów zajmuje tyle samo czasu, co pisanie kodu,
i dlatego zawsze stara si wyciga z nich wnioski. Kady wykryty bd jest nauk na przyszo,
jak unikn powtórki takiej sytuacji lub jak rozpozna, e miaa ona miejsce.
Usuwanie bdów to trudna i nieprzewidywalnie czasochonna sztuka, dlatego naley zro-
bi wszystko, aby mie z ni jak najmniej do czynienia. Sposobów na skrócenie czasu usuwania
usterek jest wiele, np. staranne opracowywanie projektu, pisanie w dobrym stylu, sprawdzanie
126
5. USUWANIE BDÓW
warunków brzegowych, stosowanie asercji i testów sensownoci, programowanie defensywne,
projektowanie dobrych interfejsów, ograniczanie iloci danych globalnych oraz korzystanie
z narzdzi diagnostycznych. Profilaktyka zawsze jest lepsza od leczenia.
Jaka jest rola jzyka? Najwiksz si od zawsze ksztatujc ewolucj jzyków programo-
wania jest ch zapobiegania wystpowaniu bdów poprzez odpowiednie dobranie waciwoci
jzyka. Niektóre cechy jzyków programowania pozwalaj wyeliminowa cae grupy bdów, np.
sprawdzanie zakresu w operacjach indeksowania, ograniczenie lub wrcz wyczenie moliwoci
stosowania wskaników, automatyczne odzyskiwanie pamici, acuchowe typy danych, kon-
trola typów wejcia-wyjcia i rygorystyczna kontrola typów. Z drugiej strony pewne wasnoci
jzyków zwikszaj prawdopodobiestwo powstawania bdów: instrukcje goto, zmienne globalne,
nieograniczony dostp do wskaników i automatyczne konwersje typów. Programici powinni
wiedzie, które waciwoci jzyka s potencjalnie ryzykowne, i zachowa szczególn ostro-
no przy ich uywaniu. Ponadto powinni wczy wszystkie narzdzia diagnostyczne kom-
pilatora i zwraca uwag na zgaszane przez niego ostrzeenia.
Waciwoci jzykowe, które uniemoliwiaj powstawanie pewnych bdów, maj swoj cen.
Jeli jzyk programowania wysokiego poziomu automatycznie usuwa niektóre bdy, cen jest
to, e atwiej jest nam popenia bdy wyszego poziomu. aden jzyk nie sprawi, e cakiem
przestaniemy popenia bdy.
Chocia wolelibymy, aby byo inaczej, kady programista najwicej czasu spdza na testo-
waniu kodu i usuwaniu bdów. W tym rozdziale omówimy techniki produktywnego i szyb-
kiego usuwania bdów. Do testowania wrócimy jeszcze w rozdziale 6.
5.1. Programy diagnostyczne
Kompilatory najwaniejszych jzyków programowania s wyposaone w zaawansowane pro-
gramy diagnostyczne (ang. debugger). Narzdzia takie wchodz w skad wielu zintegrowanych
rodowisk programistycznych oferujcych w jednym pakiecie narzdzia do pisania i edytowa-
nia kodu, kompilacji oraz wykonywania utworzonych programów. Programy diagnostyczne
maj graficzne interfejsy, za pomoc których mona wykonywa kod programu po jednej in-
strukcji lub funkcji albo zatrzymywa wykonywanie po wykonaniu okrelonych wierszy lub
spenieniu zdefiniowanych warunków. Ponadto oferuj moliwo formatowania i wywietla-
nia biecych wartoci zmiennych.
Program diagnostyczny mona uruchomi bezporednio, jeli wiadomo, e wystpi bd.
Niektóre takie programy automatycznie przejmuj sterowanie, gdy wykryj, i co si nie po-
wiodo w czasie wykonywania programu. Zwykle wykrycie miejsca wystpienia bdu jest nie-
trudne. W tym celu naley tylko sprawdzi sekwencj funkcji, które byy w tym czasie wykonywane
(stos wywoa) oraz wywietli wartoci zmiennych lokalnych i globalnych. Tyle informacji
czsto wystarcza do znalezienia róda problemu. Jeli to zawiedzie, mona skorzysta z punk-
tów wstrzymania i funkcji wykonywania programu krok po kroku, aby znale miejsce, w którym
po raz pierwszy wystpiy jakie anomalie.
W rkach dowiadczonego programisty korzystajcego z dobrego rodowiska program dia-
gnostyczny moe by bardzo efektywnym i wydajnym narzdziem, które pozwala zaoszczdzi
mnóstwo nerwów. Skoro dostpne s tak wspaniae narzdzia, po co kto miaby usuwa bdy,
nie korzystajc z ich pomocy? Po co usuwaniu bdów powica a cay rozdzia?
Istnieje ku temu kilka dobrych powodów, zarówno obiektywnych, jak i wynikajcych z na-
szego osobistego dowiadczenia. Dla niektórych jzyków spoza gównego nurtu nie ma adne-
go programu diagnostycznego albo, jeeli jest, jego funkcjonalno jest bardzo ograniczona.
5.2. DOBRE POMYSY, ATWE BDY
127
Ponadto dziaanie narzdzi diagnostycznych zaley od systemu operacyjnego, a wic nie zaw-
sze moesz mie dostp do swoich ulubionych programów tego rodzaju. Programy diagno-
styczne sabo radz sobie z niektórymi rodzajami programów, np. wieloprocesowymi i wielowt-
kowymi, systemami operacyjnymi i systemami rozproszonymi. W takich przypadkach konieczne
jest uycie technik niszego poziomu. Programista jest wówczas zdany na siebie, do dyspozycji
ma tylko instrukcje drukujce oraz wasne dowiadczenie i umiejtno analizowania kodu.
Osobicie staramy si nie naduywa programów diagnostycznych i ograniczamy si do
sprawdzenia za ich pomoc stosu wywoa oraz wartoci paru zmiennych. Jednym z powodów
podjcia takiej decyzji jest to, e mona bardzo atwo pogubi si w skomplikowanej pltaninie
struktur danych i cieek wykonawczych. Naszym zdaniem wykonywanie kodu krok po kroku
jest mniej produktywne ni jego dokadniejsze przeanalizowanie oraz dodanie kilku instrukcji
wyjciowych i samosprawdzajcego si kodu w krytycznych miejscach. Na przejrzenie danych
zwróconych przez kilka roztropnie rozmieszczonych instrukcji drukujcych potrzeba mniej
czasu ni na wykonywanie kolejnych instrukcji za pomoc klikni mysz. Podjcie decyzji,
gdzie wstawi instrukcj drukowania, zajmuje mniej czasu ni przechodzenie do krytycznego
fragmentu kodu po jednej instrukcji, nawet jeli dokadnie wiadomo, które to miejsce. Co
waniejsze, instrukcje diagnostyczne pozostaj w programie, a sesje programu diagnostycznego
znikaj.
Szukanie bdów po omacku za pomoc programu diagnostycznego rzadko bywa produk-
tywne. O wiele lepiej jest uy go do sprawdzenia stanu programu w chwili wystpienia usterki
i na podstawie zdobytych informacji zastanowi si, jak mogo do tej sytuacji doj. Programy
diagnostyczne bywaj niezwykle skomplikowane i trudne do opanowania. Zwaszcza poczt-
kujcy programista moe mie z nich sto pociech i tysic utrapie. Jeli programowi diagno-
stycznemu zada si niewaciwe pytanie, to zwykle zwróci on odpowied, ale nie wiadomo, czy
poprawn.
Mimo to program diagnostyczny moe by niezwykle pomocny i kady programista powinien
mie go pod rk. W wielu przypadkach jest to pierwsze narzdzie, z którego pomocy si ko-
rzysta. Jeli jednak nie masz programu diagnostycznego albo napotkasz wyjtkowo trudny do
rozwizania problem, dziki technikom opisanym w tym rozdziale i tak szybko wyjdziesz z opresji.
Ponadto nauczysz si dziki nim efektywniej korzysta z programów diagnostycznych, gdy
dotycz tego, jak analizowa bdy i szuka ich prawdopodobnych przyczyn.
5.2. Dobre pomysy, atwe bdy
Oho! Co jest nie tak. Mój program pad, wydrukowa bzdury albo nie chce przesta dziaa.
Co robi?
Pocztkujcy programici w takich sytuacjach najczciej zrzucaj win na kompilator, bi-
bliotek i wszystko, tylko nie ich kod. Dowiadczeni programici te by tak chcieli, ale bdc
realistami, doskonale wiedz, e wikszo bdów powstaje wycznie z ich winy.
Na szczcie gównie robimy proste bdy, które mona wyeliminowa prostymi technikami.
Przeanalizuj zwrócone przez program bdne dane i spróbuj wywnioskowa, w jaki sposób mogy
powsta. Przejrzyj dane diagnostyczne wyprodukowane przed wystpieniem awarii. Jeli masz
tak moliwo, sprawd stos wywoa. Po wykonaniu tych czynnoci bdziesz ju mie jakie
pojcie na temat tego, co i gdzie si stao. Przemyl to. Jak mogo do tego doj? Przeanalizuj
zachowanie programu od pocztku i zastanów si, co mogo spowodowa jego wadliwe dziaanie.
Diagnostyka bdów wymaga analizowania w mylach przeszoci, podobnie jak wykrywa-
nie sprawców morderstw. Zdarzyo si co niemoliwego, a jedyna informacja, jak posiadamy,
128
5. USUWANIE BDÓW
to fakt, e rzeczywicie miao to miejsce. Aby odkry przyczyn problemów, musimy si cofn
w czasie. Po znalezieniu penego wyjanienia bdziemy wiedzie, jak naprawi program, a przy
okazji prawdopodobnie odkryjemy jeszcze kilka innych rzeczy, których si nie spodziewalimy.
Szukaj znajomych wzorców. Odpowiedz sobie na pytanie, czy ju co takiego widziae. Od-
powied typu „Gdzie ju to widziaem” zwykle stanowi pierwszy krok do zrozumienia, a nie-
jednokrotnie oznacza nawet rozwizanie. Czsto wystpujce bdy maj pewne cechy szcze-
gólne. Przykadowo pocztkujcy programici czsto pisz tak:
? int n;
? scanf("%d", n);
zamiast tak:
int n;
scanf("%d", &n);
co zwykle koczy si prób odczytu danych z miejsca poza wyznaczonym obszarem pami-
ci przy pobieraniu wiersza danych wejciowych. Wykadowcy jzyka C natychmiast rozpoznaj
ten problem.
Niewyczerpanym ródem prostych bdów s le dobrane typy danych i ich konwersje
w funkcjach printf i scanf:
? int n = 1;
? double d = PI;
? printf("%d %f\n", d, n);
Znakiem szczególnym tego rodzaju bdu jest czasami pojawienie si niedorzecznych war-
toci: wielkich liczb cakowitych albo niewiarygodnie maych lub duych wartoci zmienno-
przecinkowych. Powyszy program uruchomiony na komputerze SPARC firmy Sun zwróci
nastpujc astronomiczn liczb (z koniecznoci podzielon na kilka wierszy):
1074340347 268156158598852001534108794260233396350\
1936585971793218047714963795307788611480564140\
0796821289594743537151163524101175474084764156\
422771408323839623430144.000000
Kolejny pospolity bd dotyczy wczytywania liczb typu double za pomoc funkcji scanf
przy uyciu cigu %f zamiast %lf. Niektóre kompilatory wyapuj takie bdy, poniewa
sprawdzaj zgodno typów argumentów funkcji scanf i printf z acuchami formatu. Przy
wczonych wszystkich ostrzeeniach kompilator gcc w systemie GNU dla powyszego wywo-
ania funkcji printf zwróci nastpujce informacje:
x.c:9: warning: int format, double arg (arg 2)
x.c:9: warning: double format, different type arg (arg 3)
Kolejny rodzaj bdu, który atwo rozpozna po znakach szczególnych, to brak inicjalizacji
zmiennej lokalnej. Wynikiem tego zaniedbania jest zwykle niesychanie dua warto, bdca
pozostaoci po tym, co uprzednio znajdowao si w tym miejscu w pamici. Niektóre kompi-
latory mog przestrzega przed takimi bdami, aczkolwiek do tego konieczne moe by w-
5.2. DOBRE POMYSY, ATWE BDY
129
czenie opcji sprawdzania podczas kompilacji, a poza tym — aden kompilator nie wychwyci
wszystkiego. Take pami alokowana za pomoc takich funkcji, jak malloc, realloc i new,
moe by bezuyteczna, jeli nie zostanie zainicjalizowana.
Przeanalizuj ostatni zmian. Jakie zmiany w programie zostay ostatnio wprowadzone? Jeli
rozwijajc program, za kadym razem dodajesz do niego tylko jedn rzecz, to s wycznie dwie
moliwoci: nowy kod spowodowa wystpienie bdu albo ujawni bd w starym kodzie.
W znalezieniu problemu pomocne jest dokadne przejrzenie ostatnich zmian. Jeli bd wyst-
puje w nowej wersji programu, a nie ma go w starszej, to nowy kod jest czci problemu. Dla-
tego trzeba zawsze zachowywa przynajmniej poprzedni wersj programu, aby w razie kopo-
tów móc porówna zachowanie z najnowsz wersj. Ponadto naley prowadzi rejestr
wprowadzanych zmian i naprawianych bdów, by nie musie zdobywa tych informacji na
nowo, gdy trzeba bdzie naprawi kolejny bd. Pomocne s w tym systemy kontroli kodu ró-
dowego i inne techniki ledzenia historii zmian.
Nie popeniaj dwukrotnie tego samego bdu. Gdy naprawisz jaki bd, zastanów si, czy nie
móg on wystpi jeszcze gdzie indziej. Taka sytuacja przydarzya si jednemu z nas krótko
przed rozpoczciem pisania tego rozdziau. Miao to miejsce w prostym, pisanym dla kolegi
prototypie przedstawiajcym schemat obsugi opcjonalnych argumentów:
? for (i = 1; i < argc; i++) {
? if (argv[i][0] != '-')
/* Koniec opcji */
? break;
? switch (argv[i][1]) {
? case 'o':
/* Nazwa pliku wyjciowego */
? outname = argv[i];
? break;
? case 'f':
? from = atoi(argv[i]);
? break;
? case 't':
? to = atoi(argv[i]);
? break;
? ...
Niedugo po wypróbowaniu programu kolega poinformowa nas, e do nazwy pliku zawsze
doczany by przedrostek -o. Byo nam wstyd, ale bd okaza si atwy do naprawienia. Po-
prawilimy jedn instrukcj:
outname = &argv[i][2];
Po naprawieniu tego bdu i odesaniu programu do uytkownika niebawem przysza ko-
lejna wiadomo. Tym razem program niepoprawnie obsugiwa argumenty typu -f123: po
konwersji warto liczbowa zawsze wynosia zero. To ten sam bd, co wczeniej. Poprawilimy
zatem nastpn klauzul case:
from = atoi(&argv[i][2]);
Poniewa autor si spieszy, nie zauway, e ten sam bd wystpowa jeszcze w dwóch in-
nych miejscach, przez co zanim udao si ostatecznie oczyci program z kilku wystpie iden-
tycznego bdu, potrzebna bya jeszcze jedna wymiana dowiadcze z naszym koleg.
130
5. USUWANIE BDÓW
W atwym kodzie nietrudno popeni bd, poniewa widzc znany problem, przestajemy
by ostroni. Nawet jeli kod jest tak prosty, e mógby go napisa z zamknitymi oczami, lepiej
nie zamykaj oczu podczas jego pisania.
Nie odkadaj poprawiania bdów na póniej. Popiech przy wykonywaniu pracy moe mie
szkodliwe skutki take w innych sytuacjach. Nigdy nie ignoruj awarii. Zawsze od razu popraw
bd, bo moe si nie powtórzy, a bdzie za póno. Synny sta si przykad takiego niedopa-
trzenia w misji sondy „Pathfinder” wysanej na Marsa. Po jej pomylnym ldowaniu na po-
wierzchni planety w lipcu 1997 roku komputery pokadowe resetoway si mniej wicej raz na
dzie, co stanowio wielk zagadk dla inynierów. Gdy znaleli przyczyn problemów, zdali
sobie spraw, e mieli ju z tym do czynienia. Takie zachowania komputerów zdarzay si ju
w fazie wstpnych testów, ale zostay zlekcewaone, poniewa inynierowie pracowali wówczas
nad czym innym. Zostali wic zmuszeni do zajcia si tym dopiero póniej, gdy maszyna
znajdowaa si miliony kilometrów od nich i znacznie trudniej byo j naprawi.
Sprawdzaj stos wywoa. Mimo i programy diagnostyczne pozwalaj bada programy pod-
czas dziaania, to najczciej s wykorzystywane do analizowania stanu programu, który prze-
sta dziaa. Do najbardziej przydatnych informacji dostarczanych przez program diagnostycz-
ny naley numer wiersza kodu ródowego, w którym wystpi problem. Cenn wskazówk s
równie nieprawdopodobne wartoci argumentów (puste wskaniki, bardzo due wartoci ca-
kowite, podczas gdy spodziewane s mae, ujemne wartoci tam, gdzie powinny by dodatnie,
acuchy znaków nienalecych do alfabetu).
Oto typowy przykad z opisu algorytmów sortowania przedstawionego w rozdziale 2. Aby
posortowa tablic liczb cakowitych, naley wywoa funkcj qsort, przekazujc jej jako ar-
gument funkcj icmp porównujc liczby cakowite:
int arr[N];
qsort(arr, N, sizeof(arr[0]), icmp);
Zaómy, e pomykowo podano nazw scmp funkcji porównujcej acuchy:
? int arr[N];
? qsort(arr, N, sizeof(arr[0]), scmp);
Jako e kompilator w tym przypadku nie moe wykry niezgodnoci typów, nieuchronnie
napytalimy sobie biedy. Program ulega awarii spowodowanej prób dostpu do niedozwolo-
nego miejsca w pamici. Program diagnostyczny dbx zwraca nastpujce informacje o stosie
wywoa (przeredagowane, aby zmieciy 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 nastpia w funkcji strcmp. Wida, e przekazywane do
niej dwa wskaniki s o wiele za mae, co niewtpliwie jest oznak kopotów. W stosie wywoa
zostay podane orientacyjne numery wierszy, w których nastpio wywoanie kadej funkcji.
Wiersz nr 13 w naszym pliku badqs.c zawiera takie wywoanie:
5.3. BRAK POMYSÓW, TRUDNE BDY
131
return strcmp(v1, v2);
wskazujce na ródo bdu.
Przy uyciu programu diagnostycznego mona równie wywietli wartoci zmiennych lo-
kalnych i globalnych, które take mog naprowadzi nas na jaki trop.
Najpierw przeczytaj, a potem poprawiaj. Jedn z najbardziej niedocenianych efektywnych
technik wykrywania bdów jest uwane przeczytanie kodu i zastanowienie si nad nim bez do-
konywania jakichkolwiek zmian. Pokusa, aby chwyci za klawiatur i zacz wprowadza zmiany,
jest bardzo dua, ale naley si jej oprze. Istnieje due 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 najwaniejszej czci programu na papierze pozwala spojrze na niego z nieco innej
perspektywy, ni ogldajc go na ekranie, i zachca do refleksji. Nie stosuj jednak tej techniki
rutynowo. Drukowanie kodu programu to marnotrawstwo drzew, a poza tym i tak trudno
ogarn ca struktur kodu, jeli zajmuje on kilka stron. Co wicej, po wprowadzeniu pierw-
szej zmiany cay wydruk nadaje si do wyrzucenia.
Zrób sobie krótk przerw. Czasami w kodzie widzisz to, co chciaby widzie, a nie to, co
jest w nim rzeczywicie zapisane. Jeli na chwil si oderwiesz, to po powrocie moe zaczniesz
wicej uwagi zwraca na prawdziwe znaczenie kodu.
Oprzyj si pokusie poprawiania kodu natychmiast. Warto chwil si przed tym zastanowi.
Objanij swój kod komu innemu. Dobrym sposobem jest objanienie napisanego przez siebie
kodu innej osobie. Zdarza si, e w ten sposób sami odkrywamy sedno problemu. Czasami wy-
starczy tylko powiedzie kilka zda, aby stwierdzi ze wstydem: „Niewane, ju wiem, co jest
nie tak. Przepraszam, e Ci przeszkadzam”. To niezwykle skuteczna metoda. W rol suchacza
moe si wcieli nawet osoba niebdca programist. W pewnym uniwersyteckim orodku
komputerowym przy stanowisku pracy pomocy technicznej umieszczono pluszowego misia.
Studenci chccy uzyska pomoc najpierw musieli swój problem objani misiowi i dopiero po-
tem mogli porozmawia z czowiekiem.
5.3. Brak pomysów, trudne bdy
„Nie mam zielonego pojcia, o co moe chodzi”. Jeli kompletnie nie wiesz, w czym moe
tkwi problem, to zaczynaj si schody.
Wymu powtarzalno bdu. Pierwsz czynnoci, któr naley wykona, jest sprawienie,
aby bd pojawia si na danie. Tropienie bdu pojawiajcego si tylko raz na jaki czas nie
jest przyjemne. Powi chwil na sporzdzenie danych wejciowych i opracowanie takich pa-
rametrów, które pozwol Ci niezawodnie spowodowa wystpienie bdu za kadym razem.
Nastpnie zapakuj to wszystko w jeden pakiet, aby móc go przywoywa jednym przyciskiem
albo kilkoma klawiszami. Jeli bd jest trudny do wytropienia, czynnoci te trzeba bdzie po-
wtórzy wielokrotnie, a wic lepiej je sobie maksymalnie uproci.
Jeli bdu nie da si odtworzy za kadym razem, spróbuj zrozumie dlaczego. Czy czsto-
tliwo jego wystpowania zaley od jakich specyficznych warunków? Nawet jeeli nie moesz
wymusi pojawienia si bdu za kadym razem, warto spróbowa przynajmniej skróci czas
oczekiwania na jego wystpienie.
Jeli program moe dostarcza danych diagnostycznych, skorzystaj z tej moliwoci. Pro-
gramy symulacyjne, takie jak program generujcy acuchy Markowa z rozdziau 3., powinny
zawiera opcj generowania danych diagnostycznych, np. w celu sprawdzenia wartoci pocztkowej
132
5. USUWANIE BDÓW
generatora liczb losowych, dziki którym mona spróbowa odtworzy uzyskane wyniki. Wiele
programów zawiera takie opcje i warto je uwzgldni take w swoich programach.
Dziel i rzd. Czy dane wejciowe wywoujce awari programu mona jako zmniejszy albo
bardziej skoncentrowa? Stwórz minimalny zestaw danych wejciowych, które powoduj wy-
stpowanie bdu, aby zredukowa liczb moliwoci. Jakie zmiany powoduj, e bd przestaje
si pokazywa? Spróbuj wyodrbni takie przypadki testowe, które precyzyjnie koncentruj si
na szukanym bdzie. Kady taki przypadek powinien by zaplanowany na uzyskanie okrelone-
go wyniku, potwierdzajcego lub wykluczajcego pewn hipotez na temat róda problemów.
Uyj algorytmu przeszukiwania binarnego. Odrzu poow danych wejciowych i sprawd,
czy program nadal zwraca niepoprawny wynik. Jeli nie, wró do poprzedniego stanu i odrzu
drug poow danych wejciowych, a pierwsz tym razem pozostaw. T sam metod mona
zastosowa w odniesieniu do tekstu programu. Usu jak cz kodu ródowego, która Twoim
zdaniem nie powinna mie zwizku z wystpujcym bdem, i sprawd, co si stanie. Przy ma-
nipulowaniu duymi przypadkami testowymi i duymi ilociami kodu ródowego programu
bardzo pomocny jest edytor kodu z opcj cofania zmian, która zapewnia, e nie utracimy bdu.
Przeprowad numeryczn analiz usterek. Czasami na trop bdu mona wpa, analizujc
pewne liczbowe cechy usterki. Po napisaniu jednego z podrozdziaów tej ksiki spostrzegli-
my, e niektóre litery gdzie si z niego ulotniy. To byo bardzo dziwne. Poniewa tekst zo-
sta skopiowany i wklejony do pliku z innego miejsca, doszlimy do wniosku, e problem tkwi
w funkcji kopiowania lub wklejania edytora tekstu. Ale od czego rozpocz poszukiwanie b-
du? Postanowilimy dokadniej przyjrze si danym i odkrylimy, e braki znaków wystpuj
w równych odstpach w tekcie. Obliczylimy, e odlego midzy dwoma kolejnymi brakami
zawsze wynosia 1 023 bajty. Taka regularno jest bardzo podejrzana. Poszukalimy w kodzie
ródowym edytora wartoci zblionych do 1 024 i znalelimy kilka rzeczy wartych uwagi.
Jedna z nich znajdowaa si w wieo napisanym kodzie, a wic postanowilimy zacz od niej.
Szybko spostrzeglimy bd. Bya to klasyczna pomyka o jeden, która powodowaa, e zerowy
bajt kasowa ostatni znak w buforze o rozmiarze 1 024 bajtów.
Na trop bdu wpadlimy dziki przeanalizowaniu liczbowych waciwoci zwizanych z uster-
k. Ile czasu nam to zajo? Kilka minut spdzilimy w osupieniu, pi minut zajo nam od-
krycie prawidowoci w znikaniu znaków i kolejnych piciu minut potrzebowalimy na znale-
zienie i usunicie bdu. Rozwizanie tego problemu przy uyciu programu diagnostycznego
byoby bardzo trudne, gdy w gr wchodziy dwa wieloprocesowe programy obsugiwane za
pomoc myszy i komunikujce si ze sob poprzez system plików.
Wywietlaj dodatkowe informacje, aby zorientowa si, jak dziaa program. Jeli nie rozu-
miesz, co robi kod, to najatwiejszym i najmniej kosztownym wydajnociowo sposobem na do-
wiedzenie si tego jest dodanie instrukcji wywietlajcych róne informacje. W ten sposób
mona upewni si co do susznoci swoich ocen lub zweryfikowa hipotezy na temat tego, co
dziaa le. Jeli np. wydaje Ci si, e niemoliwe jest dotarcie do pewnej czci kodu, dodaj in-
strukcj wywietlajc informacj: „Nie mona tu wej”. Jeeli póniej komunikat ten zosta-
nie pokazany, przesu wywietlajc go instrukcj nieco wyej, aby dowiedzie si, w którym
miejscu zaczynaj si kopoty. Analogicznie moesz te wywietla informacj: „Udao si tu
wej” i przesuwa j stopniowo coraz dalej, by znale ostatnie miejsce, w którym nic zego si
nie dzieje. Komunikaty powinny róni si od siebie, aby za kadym razem byo wiadomo,
który zosta wywietlony.
Komunikaty powinny by zwize i zawsze mie jednakowy format, aby daway si atwo
przeanalizowa programicie lub programom pomocniczym, takim jak np. narzdzie grep su-
ce do porównywania wzorców. Programy podobne do grep s nieocenionym wsparciem przy
5.3. BRAK POMYSÓW, TRUDNE BDY
133
przeszukiwaniu tekstu — prost implementacj takiego narzdzia przedstawiamy w rozdziale 9.
Jeli wywietlasz wartoci zmiennych, to za kadym razem formatuj komunikat w taki sam
sposób. W jzykach C i C++ wskaniki prezentuj w postaci liczb szesnastkowych przy uyciu
specyfikatorów formatu %x lub %p. Dziki temu dowiesz si, czy dwa wskaniki maj t sam
warto bd s ze sob w jaki sposób powizane. Naucz si odczytywa wartoci wskaników
oraz rozpoznawa prawdopodobne i nieprawdopodobne wartoci, np. zero, liczby ujemne, nie-
typowe wartoci i mae liczby. Take znajomo formatów adresów przydaje si podczas uy-
wania programu diagnostycznego.
Jeli jest moliwo, e program zwróci bardzo du ilo danych, to moe dane te wystar-
czy wydrukowa w postaci pojedynczych liter, np. A, B itd., aby zwile pokaza, dokd pro-
gram doszed.
Pisz samosprawdzajcy si kod. Jeli potrzebujesz wicej informacji, to moesz napisa wa-
sn funkcj sprawdzajc okrelony warunek, wywietlajc wartoci odpowiednich zmiennych
i zamykajc program:
/* check: sprawdza warunek, drukuje i koczy dziaanie */
void check(char *s)
{
if (var1 > var2) {
printf("%s: var1 %d var2 %d\n", s, var1, var2);
fflush(stdout);
/* Zapewnia wysanie wszystkich danych na wyjcie */
abort();
/* Sygnalizuje nienormalne zakoczenie dziaania programu */
}
}
Funkcja check wywouje standardow funkcj jzyka C o nazwie abort, która przedwcze-
nie koczy dziaanie programu w celu umoliwienia jego analizy w programie diagnostycznym.
Oczywicie funkcj check mona te zmieni w taki sposób, aby po wydrukowaniu informacji
nie zamykaa programu.
Nastpnie wywoaj funkcj check wszdzie tam, gdzie tego potrzebujesz:
check("Przed podejrzanym kodem");
/* … Podejrzany kod … */
check("Za podejrzanym kodem");
Po naprawieniu bdu nie usuwaj funkcji check z kodu ródowego. Umie j w komenta-
rzu albo wycz j za pomoc opcji programu diagnostycznego, aby móc jej uy ponownie, gdy
wystpi kolejny trudny do rozwizania problem.
Jeli pojawi si takie problemy, zakres obowizków funkcji mona rozszerzy np. o weryfikacj
i wywietlanie struktur danych. Mona nawet zastosowa bardziej ogólne podejcie i napisa
procedur na bieco 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 czci programu. Wówczas w razie
kopotów mona je bez przeszkód wczy. Nie ograniczaj si do korzystania z nich tylko pod-
czas usuwania bdów. Moesz ich uywa we wszystkich fazach rozwoju programu, a jeli nie
pochaniaj zbyt duo zasobów, to nawet warto je pozostawi wczone cay czas. W duych
programach, takich jak systemy komutacyjne w komunikacji, czsto znaczn cz kodu stanowi
podprogramy monitorujce przepywajce informacje i sprzt i zgaszajce wszelkie usterki,
niekiedy nawet automatycznie je naprawiajc.
134
5. USUWANIE BDÓW
Utwórz dziennik. Kolejnym sposobem jest utworzenie pliku dziennika, w którym bd zapi-
sywane dane diagnostyczne w cile okrelonym formacie. W razie wystpienia awarii w pliku
takim powinien znale si zapis tego, co dziao si tu przed tym wydarzeniem. Serwery sie-
ciowe i inne programy dziaajce w sieci utrzymuj dzienniki, w których zapisuj ogromne iloci
informacji o ruchu sieciowym — na ich podstawie kontroluj siebie i swoich klientów. Poniej
przedstawiamy fragment takiego pliku pochodzcego z lokalnego systemu (tekst dopasowany
do 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 pojawiy si rekordy danych, trzeba pamita o zapisaniu w nim
zawartoci buforów wejcia i wyjcia. Funkcje wyjciowe, takie jak printf, zwykle buforuj
swoje wyniki, aby zoptymalizowa dziaanie operacji drukowania. Przy nienormalnym zako-
czeniu pracy programu informacje te mog zosta utracone. W jzyku C zapisanie wszystkich
tego typu danych przed zamkniciem programu mona wymusi za pomoc funkcji fflush. Jej
odpowiednikiem w jzykach C++ i Java jest funkcja flush zapisujca dane ze strumieni wyj-
ciowych. Jeeli nie przeszkadzaj Ci dodatkowe koszty wydajnociowe, problem moesz roz-
wiza raz na zawsze, wyczajc buforowanie operacji zapisu danych w dzienniku. Su do
tego standardowe funkcje o nazwach setbuf i setvbuf. Wywoanie funkcji setbuf(fp, NULL)
spowoduje wyczenie buforowania w strumieniu fp. Standardowe strumienie bdów (stderr,
cerr
i System.err) maj domylnie wyczone buforowanie.
Rysuj obrazy. Czasami w testowaniu i usuwaniu bdów doskona pomoc s obrazy. Oczywi-
cie najbardziej pomagaj w zrozumieniu struktur danych, o czym przekonalimy si w roz-
dziale 2., i w pisaniu programów graficznych, ale to nie jedyne ich zastosowania. Na wykresie
punktowym lepiej wida rozkad wartoci ni w kolumnach liczb. Na histogramie mona a-
twiej wychwyci anomalie w ocenach z egzaminów, losowych liczbach, rozmiarach kubeków
alokowanych przez specjalne funkcje i uywanych w tablicach mieszania itd.
Jeli nie rozumiesz, co dzieje si w Twoim programie, spróbuj sobie pomóc, opatrujc
struktury danych danymi statystycznymi, które dodatkowo przedstaw w postaci wykresu. Po-
niej zaprezentowano wykresy sporzdzone dla programu Markowa z rozdziau 3. w wersji na-
pisanej w jzyku C. Na o x zostay naniesione dugoci acuchów mieszania, a na o y — licz-
by elementów w tych acuchach. Jako danych wejciowych uylimy naszego standardowego
tekstu z Ksigi Psalmów (42 685 sów, 22 482 przedrostki). Pierwsze dwa wykresy zostay spo-
rzdzone dla dobrych mnoników 31 i 37, a trzeci — dla koszmarnej wartoci 128. W dwóch
pierwszych przypadkach dugo adnego acucha nie przekracza 15 lub 16 elementów, a wik-
szo acuchów skada si z 5 i 6 elementów. W trzecim przypadku dane s bardziej rozpro-
szone, najduszy acuch ma 187 elementów i wystpuje bardzo duo acuchów zawieraj-
cych po 20 i wicej elementów.
5.4. OSTATNIA DESKA RATUNKU
135
Korzystaj z narzdzi. Dobrze uyj narzdzi oferowanych przez swoje rodowisko pracy. Na
przykad program porównujcy pliki, taki jak diff, zestawia wyniki programu, którego wyko-
nywanie zakoczyo si powodzeniem, i takiego, którego wykonywanie zakoczyo si niepo-
wodzeniem, dziki czemu mona przeanalizowa rónice. Jeli program diagnostyczny zwraca
due iloci danych, to przeszukuj je za pomoc takiego programu jak grep oraz analizuj przy
uyciu edytora. Wstrzymaj si od drukowania na papierze danych diagnostycznych: kompute-
ry lepiej radz sobie z analiz duych iloci danych ni ludzie. Uyj skryptów powoki, aby
zautomatyzowa proces przetwarzania danych diagnostycznych.
Pisz proste programy do weryfikacji hipotez i swojego zrozumienia sposobu dziaania kodu.
Czy mona np. zwolni pusty wskanik?
int main (void)
{
free(NULL);
return 0;
}
Programy do kontroli kodu ródowego, takie jak RCS, umoliwiaj rejestracj kolejnych
wersji programu, dziki czemu mona sprawdzi, jakie zmiany zostay wprowadzone, i w razie
potrzeby przywróci jedn ze starszych wersji. Oprócz funkcji podgldu najnowszych zmian
programy te oferuj równie moliwo znalezienia najczciej modyfikowanych fragmentów
kodu. W tych miejscach czsto kryj si rozmaite bdy.
Pisz dokumentacj. Jeli poszukiwania róda problemów bd si przeciga, po pewnym
czasie zapomnisz, co ju zostao sprawdzone, a czego jeszcze nie wiesz. Jeeli zaczniesz zapisy-
wa wykonane testy i ich wyniki, to bdziesz mie pewno, e niczego nie przeoczysz. Notujc
informacje o problemie, lepiej zapamitasz, e kiedy ju co podobnego widziae, a przy oka-
zji bdziesz mie pomoc, gdy zechcesz objani problem komu innemu.
5.4. Ostatnia deska ratunku
Co robi, jeli adna z wymienionych technik nie pomaga? Teraz moe nadesza pora na wy-
konanie programu krok po kroku w programie diagnostycznym. Jeli masz kompletnie bdne
wyobraenie o tym, jak co dziaa, przez co szukasz problemu w niewaciwym miejscu albo
szukasz tam, gdzie trzeba, lecz go nie widzisz, program diagnostyczny moe zmusi Ci do
136
5. USUWANIE BDÓW
spojrzenia na sprawy z innej perspektywy. Bdy niedajce si wykry z powodu niewaciwego
rozumienia istoty problemu s najgorsze. W takich przypadkach mechaniczna pomoc jest bez-
cenna.
Czasami bdne przekonanie dotyczy bardzo prostych zagadnie, s to np.: niepoprawna
kolejno wykonywania operatorów, uycie niewaciwego operatora, wcicia kodu niezgodne
z jego struktur czy bdy zakresu dostpnoci zmiennych polegajce na tym, e zmienna lo-
kalna zasania zmienn globaln albo zmienna globalna wcina si w zakres lokalny. Programi-
ci czsto zapominaj przykadowo o tym, e operatory & i | stoj dalej w kolejce do wykonania
ni operatory == i !=. Dlatego zdarza im si pisa taki kod:
? if (x & 1 == 0)
? ...
i nie mog zrozumie, dlaczego ten warunek nigdy nie jest speniony. Czasami polizgnie
si palec i omykowo zamiast jednego znaku równoci napisz si dwa albo odwrotnie:
? while ((c == getchar()) != EOF)
? if (c = '\n')
? break;
Albo podczas pracy nad programem nie zostanie usunity niepotrzebny kod:
? for (i = 0; i < n; i++);
? a[i++] = 0;
Niektóre problemy wynikaj z popiechu:
? switch (c) {
? case '<':
? mode = LESS;
? break;
? case '>':
? mode = GREATER;
? break;
? defualt:
? mode = EQUAL;
? break;
? }
Czasami wpisanie argumentów w niepoprawnej kolejnoci powoduje bd, którego nie mona
wykry 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 procedura
moe zmienia pewne globalne lub wspóuytkowane zmienne.
5.4. OSTATNIA DESKA RATUNKU
137
Nieraz uyty algorytm lub struktura danych zawieraj fatalny bd, którego po prostu nie
dostrzegamy. Przygotowujc materiay do omówienia list powizanych, sporzdzilimy pakiet
funkcji sucych do tworzenia nowych elementów listy oraz doczania ich na pocztku i ko-
cu struktury danych itp. (funkcje te mona obejrze w rozdziale 2.). Oczywicie sprawdzilimy,
czy wszystko jest w porzdku za pomoc specjalnie napisanego w tym celu programu testowego.
Kilka pierwszych testów zostao zakoczonych pomylnie, ale w pewnym momencie nastpia
efektowna awaria. Oto kod ródowy 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 kopotów sprawio nam dostrzeenie, e pierwsza ptla umieszczaa
ten sam wze p w obu listach, przez co gdy przystpowalimy do drukowania, wskaniki byy
beznadziejnie pomieszane.
Takie bdy s trudne do wykrycia, poniewa podwiadomie widzimy to, co chcielibymy
widzie. Dlatego w takich przypadkach pomocny jest program diagnostyczny, który zmusza
nas do zastanowienia si nad innymi moliwociami i przeledzenia rzeczywistego dziaania
programu zamiast mylenia o tym, co on powinien robi. Czasami problem wynika z bdu
w ogólnej strukturze programu. Aby wykry co takiego, trzeba ponownie przejrze swoje wstp-
ne zaoenia.
Zauwamy przy okazji, e w przykadzie dotyczcym list bd znajdowa si w kodzie te-
stujcym, co znacznie utrudniao jego znalezienie. To straszne, jak atwo mona zmarnowa
czas na poszukiwaniu bdów, których nie ma, bo problem tkwi w programie testujcym, albo
na testowaniu niewaciwej wersji programu tudzie poniewa zaniedbao si aktualizacj bd
kompilacj programu przed wznowieniem testowania.
Jeli mimo znacznego wysiku nie uda Ci si znale bdu, to zrób sobie przerw. Odpocznij
i chwilowo zajmij si czym innym. Porozmawiaj z koleg i popro go o pomoc. Rozwizanie
moe pojawi si nagle, nie wiadomo skd, a nawet jeli nie, po powrocie do pracy nie bdziesz
ju tkwi w tym samym zauku.
Zdarza si te, cho niezwykle rzadko, e ródem problemów jest kompilator, biblioteka,
system operacyjny, a nawet sprzt. Mona to podejrzewa zwaszcza wówczas, gdy bd wyst-
pi bezporednio po wprowadzeniu zmian w rodowisku. Nigdy nie naley rozpoczyna szuka-
nia bdów od tych miejsc, ale po wykluczeniu wszystkich innych moliwoci to moe by
ostatnie, co nam zostanie. Kiedy przenosilimy duy program do formatowania tekstu z sys-
temu Unix do komputera PC. Kompilacja zakoczya si bez adnych problemów, ale program
dziaa bardzo dziwnie: opuszcza mniej wicej co drugi znak w danych wejciowych. Pierwsz
nasz myl byo to, e ma to jaki zwizek z uywaniem 16-bitowych liczb cakowitych za-
miast 32-bitowych albo z kolejnoci bajtów. Jednak po wydrukowaniu znaków, tak jak byy przed-
stawiane ptli gównej, odkrylimy, e bd tkwi w standardowym pliku nagówka ctype.h
dostarczanym przez producenta kompilatora. Zawiera on implementacj funkcji isprint
w postaci makra funkcyjnego:
? #define isprint(c) ((c) >= 040 && (c) < 0177)
a gówna ptla pobierania danych bya zdefiniowana nastpujco:
138
5. USUWANIE BDÓW
? while (isprint(c = getchar()))
? ...
Za kadym razem, gdy na wejciu pojawiaa si spacja (o wartoci ósemkowej 40, któr sto-
suje si w zym stylu zamiast zapisu ' ') lub znak o wyszym numerze, funkcja getchar bya
wywoywana po raz drugi, poniewa makro ewaluowao swój argument dwa razy, przy czym
pierwszy znak znika bezpowrotnie. Nasz kod ródowy moe nie by szczytem elegancji —
warunek ptli mógby by prostszy — ale plik nagówkowy od dostawcy kompilatora bez naj-
mniejszych wtpliwoci zawiera bd.
Przykady tego bdu mona spotka do dzi. Ponisze makro pochodzi z wci uywanych
plików nagówkowych innego producenta:
? #define __iscsym(c) (isalnum(c) || ((c) == '_'))
Obfitym ródem bdów powodujcych nienormalne dziaanie programów s wycieki pamici,
tzn. przypadki nieodzyskania nieuywanych ju fragmentów pamici. Kolejnym jest niezamy-
kanie plików, które prowadzi do zapenienia tablicy plików otwartych, przez co nie mona
otwiera nastpnych. Awarie programów zawierajcych wycieki pamici czsto wygldaj bar-
dzo tajemniczo. Poniewa do usterki dochodzi po wyczerpaniu pewnych zasobów, nie da si
odtworzy specyficznych zdarze.
Z rzadka kopoty sprawia sprzt. W procesorze Pentium z 1994 roku wystpowa bd, któ-
ry powodowa, e niektóre obliczenia na liczbach zmiennoprzecinkowych daway ze wyniki.
Ta szeroko nagoniona usterka w projekcie urzdzenia duo firm kosztowaa, ale gdy ju j
zidentyfikowano, bd dao si powtarza. Jeden z najdziwniejszych bdów, jakie widzielimy
w swojej karierze, znajdowa si w starym programie kalkulatora dziaajcym w systemie dwu-
procesorowym. Czasami dla wyraenia 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 dao
si w aden sposób przewidzie, czy w danym przypadku wynik bdzie poprawny, czy nie.
W kocu odkryto, i ródem problemu jest usterka w jednostce odpowiedzialnej za obliczenia
zmiennoprzecinkowe w jednym z procesorów. Poniewa do wykonywania kalkulatora by lo-
sowo wybierany albo jeden, albo drugi procesor, raz wyniki byy poprawne, a innym razem
niedorzeczne.
Wiele lat temu uywalimy maszyny, której wewntrzn temperatur mona byo oszacowa na
podstawie liczby niepoprawnych bitów niskich w obliczeniach zmiennoprzecinkowych. Oblu-
zowaa si jedna z kart ukadu elektronicznego i w miar jak rosa temperatura, karta ta od-
chylaa si coraz bardziej, co powodowao, e wicej bitów zostawao odcitych od pyty mon-
taowej.
5.5. Bdy niepowtarzalne
Najtrudniejsze do wytropienia s te bdy, które pojawiaj si nieregularnie — najczciej
przyczyn ich powstawania nie jest banalne uszkodzenie sprztu. Jednak cenn wskazówk jest
ju sam fakt, e tak si zachowuj. Mona dedukowa, e prawdopodobn przyczyn bdu jest
nie usterka w algorytmie, lecz raczej to, i program korzysta z danych, które za kadym razem
s inne.
Sprawd, czy wszystkie zmienne s zainicjalizowane. Moliwe, e która z nich otrzymuje
losow warto odpowiadajc temu, co byo ostatnio zapisane w przypisywanym jej obszarze
5.5. BDY NIEPOWTARZALNE
139
pamici. W jzykach C i C++ najczstszymi sprawcami s zmienne lokalne funkcji i pami
uzyskiwana za pomoc funkcji alokujcych. Wszystkim zmiennym przypisz konkretne warto-
ci. Jeli w programie uywana 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.
Jeeli dodanie kodu diagnostycznego powoduje zmian zachowania lub wrcz zniknicie
bdu, to mona podejrzewa nieprawidowo przy alokacji pamici — jaka instrukcja zapi-
suje dane poza przydzielonym obszarem i dodanie kodu diagnostycznego wprowadza modyfi-
kacj rozmieszczenia elementów w pamici, której skutkiem jest zmiana efektu wywoywanego
przez bd. Wikszo funkcji wyjciowych, od printf po funkcje okien dialogowych, alokuje
pami samodzielnie, co dodatkowo zaciemnia obraz.
Jeli miejsce awarii wydaje si odlege od wszystkiego, co mogoby by zepsute, to najbar-
dziej prawdopodobn przyczyn problemu jest bdne zmienienie zawartoci obszaru pamici
w miejscu, które jest uywane dopiero póniej. Czasami problem dotyczy tzw. wiszcego
wskanika, czyli omykowego zwrócenia przez funkcj wskanika na zmienn lokaln i pó-
niejszego jego uycia. rodkiem profilaktycznym przed tak odroczon katastrof jest zwróce-
nie adresu zmiennej lokalnej:
? char *msg(int n, char *s)
? {
? char buf[100];
?
? sprintf (buf, "Bd %d: %s\n", n, s);
? return buf;
? }
Zanim wskanik zwrócony przez funkcj msg zostanie uyty, bdzie ju wskazywa nic nie-
znaczce miejsce w pamici. Musisz przydzieli pami za pomoc funkcji malloc, uy sta-
tycznej tablicy albo zada, aby wywoujcy dostarczy pami.
Uycie dynamicznie alokowanej wartoci ju po jej zwolnieniu objawia si w podobny spo-
sób. Wspominalimy o tym w rozdziale 2., przy okazji omawiania funkcji freeall. Poniszy
kod zawiera bd:
? for (p = listp; p != NULL; p = p->next)
? free (p);
Pamici, która zostaa zwolniona, nie wolno uywa, poniewa jej zawarto moga si
zmieni i nie ma pewnoci, e instrukcja p->next wci wskazuje waciwe miejsce w pamici.
W niektórych implementacjach funkcji malloc i free dwukrotne zwolnienie elementu po-
woduje uszkodzenie wewntrznych struktur danych, ale nie wywouje to adnych kopotów
przez duszy czas, dopóki kolejne wywoanie nie wywróci si na tym baaganie. Pewne funkcje
alokacyjne maj opcje diagnostyczne, za pomoc których mona sprawdzi spójno pola dzia-
a przed kadym wywoaniem. Wcz je, jeli próbujesz wytropi nieregularnie zachowujcy
si bd. Jeeli w ten sposób nic nie wskórasz, moesz napisa wasn funkcj alokujc, która
mogaby sprawdza niespójno swoich wasnych zachowa albo zapisywa w dzienniku
wszystkie wywoania, aby mona je byo póniej przeanalizowa. Napisanie funkcji alokujcej
pami, gdy nie zaley nam bardzo na szybkoci dziaania, jest atwe, a wic strategi t mona
wykona, jeeli problem jest powany. Istniej te wietne komercyjne narzdzia suce do
sprawdzania zarzdzania pamici oraz wykrywajce bdy i wycieki pamici. Jeli nie masz do
nich dostpu, moesz wykorzysta niektóre z ich zalet, piszc wasne funkcje malloc i free.
140
5. USUWANIE BDÓW
Jeeli jedna osoba nie ma problemów z programem, a inna ma, to znaczy, e istnieje jaka
usterka, która ujawnia si tylko w okrelonych warunkach. Odpowiedzialne za to mog by
jakie pliki wczytane przez program, prawa dostpu do plików, zmienne rodowiskowe, cieki
dostpu polece, ustawienia domylne lub pliki uywane podczas uruchamiania programu. Trudno
cokolwiek w takich sytuacjach doradzi, poniewa aby odtworzy rodowisko, w którym program
zawodzi, trzeba by t drug osob.
wiczenie 5.1. Napisz wasne wersje funkcji malloc i free, których bdzie mona uy do
rozwizywania problemów z zarzdzaniem pamici. Jednym z rozwiza moe by sprawdza-
nie w kadym wywoaniu caej przestrzeni roboczej. Odmiennym podejciem jest zapisywanie
danych diagnostycznych w dzienniku, aby mogy zosta przetworzone przez inny program.
Bez wzgldu na to, któr metod wybierzesz, na pocztku i kocu kadego alokowanego bloku
dodaj znaczniki, by ujawni ewentualne przypadki przekroczenia zakresu z obu stron.
5.6. Narzdzia diagnostyczne
W znajdowaniu bdów pomocne s nie tylko programy diagnostyczne. Istnieje wiele innych
narzdzi, które mog nam pomóc dotrze do wanych informacji w wielkich zbiorach danych,
znale anomalie lub tak zmieni ukad danych, aby atwiej mona byo zobaczy, co si dzieje.
Wiele z nich znajduje si w standardowym wyposaeniu warsztatu. Niektóre zostay napisane
w celu znalezienia konkretnego bdu lub przeanalizowania specyficznego problemu.
W tym podrozdziale omówimy prosty program o nazwie strings, który jest szczególnie
pomocny w przegldaniu plików skadajcych si gównie ze znaków niedrukowalnych, a wic
np. plików wykonywalnych i tajemniczych formatów binarnych uywanych przez niektóre
edytory tekstu. We wntrzu czsto kryj si róne cenne informacje, takie jak tekst dokumen-
tu, komunikaty o bdach i nieudokumentowanych opcjach, nazwy plików i katalogów, a take
nazwy funkcji, które mogy by wywoane przez program.
Programu strings uywamy równie do znajdowania tekstu w innych plikach binarnych.
Wiele plików graficznych zawiera znaki ASCII opisujce program, w którym zostay utworzone,
a pliki skompresowane i archiwa (np. ZIP) mog zawiera nazwy plików. Wszystkie te infor-
macje mona odkry za pomoc programu strings.
W systemach uniksowych istnieje ju implementacja programu strings, chocia nieco inna
od tej, któr przedstawimy tutaj. Rozpoznaje ona programy na wejciu i bada tylko tekst i seg-
menty danych, ignorujc tablic symboli. Za pomoc opcji -a mona j zmusi do zbadania
caego pliku.
Program strings pobiera tekst ASCII z plików binarnych, tak e mona go póniej wczy-
ta lub przetworzy przez inne programy. Jeli znaleziony komunikat o bdzie nie ma adnego
identyfikatora, to moe by trudno odgadn, jaki program go zgosi, nie mówic ju, dlacze-
go to zrobi. Wówczas moe pomóc przeszukanie podejrzanych katalogów przy uyciu polece-
nia zblionego do zapisanego niej:
% strings *.exe *.dll | grep 'Tajemniczy komunikat'
Funkcja strings wczytuje plik i drukuje wszystkie acuchy skadajce si przynajmniej
z 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 acucha */
for (i = 0; (c = getc(fin)) != EOF; ) {
if (!isprint(c))
break;
buf[i++] = c;
if (i >= BUFSIZ)
break;
}
if (i >= MINLEN)
/* Drukuje, jeli acuch jest wystarczajco dugi */
printf("%s:%.*s\n", name, i, buf);
} while (c != EOF);
}
acuch formatu %.*s uyty w wywoaniu funkcji printf pobiera dugo acucha z na-
stpnego argumentu (i), poniewa acuch (buf) nie jest zakoczony zerem.
Ptla do-while znajduje i drukuje kady acuch, a dziaanie koczy, gdy napotka znak
koca pliku. Dziki temu, e na kocu funkcji znajduje si sprawdzenie koca pliku, funkcja
getc
oraz ptle acuchowe mog mie wspólny warunek zakoczenia i jedno wywoanie funkcji
printf
moe obsugiwa koniec acucha, koniec pliku oraz zbyt dugie acuchy.
W standardowej ptli zewntrznej ze sprawdzeniem warunku na pocztku lub pojedynczej
ptli z funkcj getc i bardziej skomplikowanym kodem ródowym konieczne by byo dwu-
krotne wywoanie funkcji printf. Takie rozwizanie zastosowalimy na pocztku, ale zrobilimy
bd w instrukcji wywoujcej funkcj printf. Poprawilimy go w jednym miejscu, lecz zapo-
mnielimy o jeszcze dwóch innych („Czy popeniem ten sam bd jeszcze gdzie indziej?”).
Wówczas stao si jasne, e program trzeba napisa ponownie, aby byo w nim mniej powtó-
rze kodu. Tak doszlimy do ptli do-while.
Funkcja main programu strings wywouje funkcj strings dla kadego pliku przekazanego
jej 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 uycia: nazwy plików");
else {
for (i = 1; i < argc; i++) {
if ((fin = fopen(argv[i], "rb")) == NULL)
weprintf("Nie mona otworzy pliku %s:", argv[i]);
else {
strings(argv[i], fin);
fclose(fin);
}
}
142
5. USUWANIE BDÓW
}
return 0;
}
Moe si dziwisz, e funkcja strings nie pobiera danych ze swojego standardowego stru-
mienia wejciowego, gdy nie zostan podane adne pliki. Pocztkowo to robia. Aby wyjani,
dlaczego teraz tego nie robi, musimy opowiedzie histori pewnego bdu.
Oczywistym testem, za pomoc którego mona sprawdzi program strings, jest urucho-
mienie go na nim samym. Program dziaa prawidowo w systemie Unix, ale w systemie Win-
dows 95 polecenie
C:\> strings <strings.exe
zwrócio dokadnie pi wierszy danych:
!This program cannot be run in DOS mode
'.rdata
@.data
.idata
.reloc
Pierwszy wiersz wyglda jak komunikat o bdzie, przez co zmarnowalimy troch czasu na
dowiedzenie si, e jest to acuch zapisany w programie, a dane wyjciowe s poprawne, przy-
najmniej jak na razie. Czasami zdarza si, i sesja diagnostyczna zostaje przerwana z powodu
niezrozumienia róda pochodzenia komunikatu.
Ale danych wyjciowych powinno by wicej, wic gdzie si podziay? Wreszcie której no-
cy owiecio mnie („Gdzie ju to widziaem!”). Jest to problem z przenonoci, o którym sze-
rzej piszemy w rozdziale 8. Pierwsza wersja programu wczytywaa dane tylko ze standardowego
wejcia i uywaa do tego celu funkcji getchar. Ale w systemie Windows funkcja ta zwraca
znak koca pliku, jeli w danych tekstowych napotka konkretny bajt (0x1A, czyli znak Ctrl+Z).
To powodowao przedwczesne koczenie pracy programu.
Jest to cakowicie poprawne zachowanie, ale nie tego oczekiwalimy, biorc pod uwag na-
sze dowiadczenia z uywania programu w systemie Unix. Rozwizaniem jest otwarcie pliku
w trybie binarnym przy uyciu trybu „rb”. Ale strumie stdin jest ju otwarty i nie da si
zmieni jego trybu w aden standardowy sposób (mona by byo uy funkcji takich jak fdopen
i setmode, ale nie nale one do standardu jzyka C).W efekcie stajemy przed wyborem jednej
z kilku nieprzyjemnych moliwoci: zmusi uytkownika do podania nazwy pliku, dziki czemu
program bdzie dobrze dziaa w systemie Windows, cho jest to nietypowe rozwizanie dla
systemu Unix; po cichu tworzy niepoprawne odpowiedzi, gdy uytkownik systemu Windows
usiuje wczyta dane ze standardowego wejcia; albo zastosowa kompilacj warunkow, by
dostosowa zachowanie programu do rónych systemów, co zmniejsza jego przenono. Zde-
cydowalimy si na pierwsz z wymienionych moliwoci, poniewa dziki temu program
wszdzie bdzie dziaa tak samo.
wiczenie 5.2. Program strings drukuje acuchy zawierajce przynajmniej MINLEN znaków,
co czasami powoduje zwrócenie wikszej iloci danych, ni potrzeba. Zmodyfikuj program
strings
tak, aby przyjmowa opcjonalny argument sucy do okrelania minimalnej dugoci
acucha.
5.7. BDY POPENIONE PRZEZ INNYCH
143
wiczenie 5.3. Napisz funkcj vis kopiujc dane wejciowe na wyjcie i zamieniajc bajty
niedrukowalne, takie jak znak Backspace, znaki sterujce i znaki nienalece do zestawu ASCII
na symbole w formacie \Xhh, przy czym hh oznacza szesnastkow reprezentacj danego znaku.
W przeciwiestwie 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, jeli na wejciu otrzyma acuch \X0A? Co
mona zrobi, aby funkcja vis zwracaa niedwuznaczne wyniki?
wiczenie 5.5. Rozszerz zakres dziaania funkcji, tak aby przetwarzaa sekwencje plików, amaa
dugie wiersze w dowolnym miejscu i usuwaa wszystkie niedrukowalne znaki. Jakie jeszcze inne
zadania zgodne z przeznaczeniem programu mogaby spenia ta funkcja?
5.7. Bdy popenione przez innych
Niewielu programistów ma przyjemno tworzy nowy system od podstaw. Znacznie czciej
uywaj, modyfikuj, a wic i poprawiaj, kod napisany przez innych programistów.
Wszystko, co napisalimy do tej pory na temat znajdowania i eliminowania bdów, ma za-
stosowanie take do bdów popenionych przez kogo innego. Przed przystpieniem do pracy
konieczne jest jednak zbadanie organizacji programu oraz zrozumienie sposobu mylenia i pracy
poprzednika. W pewnym bardzo duym projekcie programistycznym uyto okrelenia „odkry-
cie”, stanowicego cakiem dobr przenoni. Zadanie polega na odkryciu, o co chodzi w ko-
dzie, którego my nie napisalimy.
W takich przypadkach bardzo pomocne s róne narzdzia. Uywajc programów do prze-
szukiwania tekstu, takich jak grep, mona znale wszystkie wystpienia wybranej nazwy. Ge-
neratory odsyaczy:g (ang. cross-referencer) pozwalaj zapozna si ze struktur programu. Wy-
kres przedstawiajcy wywoania funkcji jest pomocny, jeli nie jest zbyt duy. Wykonywanie
kodu po jednej instrukcji za pomoc programu diagnostycznego pozwala odkry kolejno zda-
rze. Zagldajc do historii wersji programu, mona dowiedzie si, jak program rozwija si w
czasie. Czste zmiany oznaczaj, e kod jest sabo zrozumiany albo podlega zmieniajcym si
wymaganiom, a wic moe stanowi potencjalne ródo bdów.
Czasami musisz szuka bdów w oprogramowaniu, za które nie odpowiadasz i którego kod
ródowy nie jest dostpny. W takich przypadkach musisz zidentyfikowa i scharakteryzowa
bd na tyle dobrze, aby móc go precyzyjnie omówi w raporcie i przy okazji opracowa jakie
dobre „obejcie” pozwalajce go wyeliminowa.
Kiedy wyda Ci si, e znalaze bd w nie swoim programie, przede wszystkim upewnij si,
i to na pewno jest bd, aby nie marnowa czasu autora i nie narazi si na utrat reputacji.
Gdy znajdziesz bd w kompilatorze, równie upewnij si, e to rzeczywicie bd kompila-
tora, a nie Twojego programu. Przykadowo w jzykach Ci C++ nie okrelono, czy operacja
bitowego przesunicia w prawo powinna wstawia bity zerowe (przesunicie logiczne), czy po-
wiela bit znaku (przesunicie arytmetyczne). Z tego powodu niektórzy pocztkujcy progra-
mici myl, e konstrukcje typu
? i = -1;
? printf ("%d\n", i >> 1);
144
5. USUWANIE BDÓW
s bdne, jeli nie zwróc oczekiwanego wyniku. Jest to jednak kwestia przenonoci, gdy
powyszy kod moe rónie si zachowywa w rozmaitych systemach i nie bdzie to oznaczao
bdu. Sprawd swój test w rónych systemach i upewnij si, e dobrze rozumiesz, co si dzieje.
Najlepiej skontroluj te definicj jzyka.
Sprawd, czy bd nie jest znany. Czy masz najnowsz wersj programu? Czy istnieje lista
poprawionych bdów? Wikszo programów jest wydawana w wielu rónych wersjach. Jeli
znajdziesz usterk w wersji 4.0b1, to wcale nie musi jej by w wersji 4.04b2 albo moe w jej
miejsce powsta nowa. W kadym razie niewielu programistów pasjonuje si poprawianiem
bdów w starszych wersjach programów.
Wreszcie postaw si w roli osoby, która otrzyma Twój raport. Na pewno chcesz dostarczy
wacicielowi programu jak najlepszy przypadek testowy. Nie bdziesz zbyt pomocny, jeli
bd uda Ci si ujawni tylko przy duych ilociach danych wejciowych, w wyszukanym ro-
dowisku albo przy zastosowaniu wielu plików pomocniczych. Postaraj si ograniczy test do
jak najmniejszego samodzielnego pakietu. Docz wszystkie mogce si przyda informacje,
takie jak wersja programu, rodzaj uytego kompilatora, system operacyjny czy opis sprztu.
Dla bdnej wersji funkcji isprint z podrozdziau 5.4 moglibymy dostarczy poniszy pro-
gram testowy:
/* Program testowy ujawniajcy bd w funkcji isprint */
int main(void)
{
int c;
while (isprint(c = getchar()) || c != EOF)
printf ("%c", c);
return 0;
}
Jako przypadek testowy moe posuy dowolny wiersz tekstu zawierajcy drukowalne znaki,
poniewa na wyjciu pojawi si tylko poowa danych wejciowych:
% echo 1234567890 | isprint_test
24680
%
Najlepsze powiadomienia o bdach to takie, które do zademonstrowania bdu wymagaj
uycia jednego lub najwyej dwóch wierszy danych wejciowych w wieym systemie i zawie-
raj rozwizanie. Wysyaj takie powiadomienia o bdach, jakie sam chciaby otrzymywa.
5.8. Podsumowanie
Przy odrobinie dobrych chci usuwanie bdów moe by dobr rozrywk, jak rozwizywanie
amigówek. Jednak bez wzgldu na to, czy nam si to podoba, czy nie, sztuk t bdziemy
uprawia czsto i regularnie. Poniewa fajnie by byo, gdyby bdy nie istniay, staramy si pi-
sa jak najlepszy kod od samego pocztku. W dobrze napisanym kodzie nie tylko jest mniej
bdów, lecz take atwiej je znale, jeli ju si pojawi.
Po zauwaeniu bdu w programie naley najpierw zastanowi si, co mona wywniosko-
wa z jego cech szczególnych. Skd móg si wzi? Czy wyglda znajomo? Czy zmienio si
co w programie? Czy w danych, które spowodoway jego wystpienie, jest co szczególnego?
Czasami wystarczy kilka dobrze dobranych przypadków testowych i kilka instrukcji drukujcych.
LEKTURA UZUPENIAJCA
145
Jeli nie ma adnych tropów, to i tak najlepiej jest zacz od dokadnego przemylenia
sprawy i próby zawenia liczby podejrzanych miejsc. Jedn z moliwoci jest stopniowe ogra-
niczanie zbioru danych wejciowych, aby uzyska niewielki zestaw powodujcy awari. Inn
moliwoci jest usuwanie po kolei fragmentów kodu ródowego, które nie powinny mie
z tym nic wspólnego. Mona do programu doda kod sprawdzajcy, który wcza si dopiero
po wykonaniu przez program okrelonej liczby dziaa. Wszystkie wymienione techniki to
elementy 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 dziaaniach wojennych.
Korzystaj take z innych pomocy. Niezwykle przydatne bywa objanienie dziaania
kodu komu innemu (choby pluszowemu misiowi). Posu si programem diagnostycznym
do sprawdzenia zawartoci stosu wywoa. Uyj którego z komercyjnych narzdzi do wykry-
wania wycieków pamici, przypadków naruszenia granic tablic, podejrzanego kodu itp. Z moliwo-
ci wykonywania kodu po jednej instrukcji skorzystaj wówczas, gdy stanie si jasne, e le ro-
zumiesz, jak dziaa kod.
Poznaj siebie i rodzaje bdów, które popeniasz. Kiedy znajdziesz i usuniesz jaki bd,
sprawd, czy w innych miejscach programu nie ma jeszcze podobnych usterek. Zastanów si,
co si stao, aby móc w przyszoci unikn powtórzenia tej sytuacji.
Lektura uzupeniajca
Mnóstwo cennych informacji na temat usuwania bdów mona znale w ksikach Steve’a
Maguire’a Writing Solid Code (Microsoft Press, 1993) i Steve’a McConella Kod doskonay
(Helion, 2010).
Skorowidz
Kobieta: Czy jest tu moja ciotka Minnie?
Driftwood: Có, moesz wej i poszuka, jeeli chcesz.
Jeli jej tu nie ma, to zapewne moesz 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
==, 17
0, 31
A
abstrakcja, 112, 208
addfront, 55
aktualizacja komentarza, 35
algorytm, 8, 193
czas dziaania, 50
dane wejciowe, 44
jasny, 86
Markowa, 70, 72, 79, 90
test, 168
podstawowy, 39, 83
porównywanie czasu dziaania, 50
przeszukiwania,
binarnego, 41
sekwencyjnego, 40
przyspieszanie, 181
rola, 39
sortowania, 42, 47
tworzenia,
acuchów elementów, 166
tekstu, 85
usuwania nieuytków, 116
wybór, 68, 182
wymagania pamiciowe, 50
wyszukiwania binarnego, 42
zakoczenie, 77
zoono,
oczekiwana, 50
pesymistyczna, 50
alokacja, 116
pamici, 24, 166, 186, 192
analiza
projektu, 8
skadniowa drzewa, 63
ANSI, 202
C, 46, 53, 202, 204
standard, 24
API, 113, 204
application programming interface, 113
argumenty makra, 29
Ariane 5, 165
arytmetyczne
przesunicie, 200
asembler, 188
asercja, 150
260
SKOROWIDZ
asocjacyjna
tablica, 86
associative array, 86
atexit, 116
automatyzacja, 7, 254
testów, 157
Awk, 9, 86, 87, 90, 158, 180, 193, 235, 237, 245
B
backwards compatibility, 215
bajty
kolejno, 201
porzdek, 211
balanced tree, 61
B-drzewo, 63
Beta wersja, 168
bezwzgldna
warto, 49
biaa skrzynka, 167
biblioteka, 202
big-endian, 218
binarne
przeszukiwanie, 46
drzewo poszukiwa, 59, 60
bitowy
operator, 17
pole, 201
bd
asercja, 150
bdne przekonanie, 136
cechy usterki, 132
diagnostyka, 127
dodanie instrukcji wywietlajcych informacje, 132
dziennik, 134
informacja, 151
innych programistów, 143
kompilatora, 143
komunikat, 118
minimalny zestaw danych wejciowych, 132
na danie, 131
nieregularny, 138
nowy, 129
obsuga, 99, 101, 117
po zmianie, 129
porównywanie plików, 135
powielenie, 129
przepenienia bufora, 164
roku 2000, 188
rozmowa z pluszowym misiem, 131
rzeczywiste dziaanie programu, 137
skadni, 21
skutki lekcewaenia, 130
sprztu, 138
strumie, 134
u jednej osoby, 140
usuwanie, 125, 147
uwane przeczytanie kodu, 131
wykres, 134
wykrywanie, 9
wymuszanie powtarzalnoci, 131
zasada obsugi, 119
znajdowanie, 147
znany, 144
boundary condition testing, 148
Bourne, 166
break, 27
Brooks, 69, 95
bsearch, 46
bucket, 64
bufor
bd przepenienia, 164
danych,
wejciowych, 187
wyjciowych, 187
rozmiar, 76
bug, 125
build, 76
C
C, 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, 243
wada, 79
zaleta, 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, 26
cel testowania, 167
cerr, 134
Chain, 80
char, 200
char **array, 40
clock, 177
Cohen, 218
comma-separated values, 94
Comparable, 47
const, 31
cost model, 191
cross-referencer, 143
CSV, 94, 95, 96, 108, 112
csvgetline, 96
ctime, 36, 153
ctype, 28
cyclic redundancy check, 67
cykliczna kontrola nadmiarowa, 67
czarna skrzynka, 167
SKOROWIDZ
261
czas
dziaania algorytmu, 50
mierzenie, 172, 177
pracy procesora, 178
uycia procesora, 177
wykonywania programu, 177
czytelne formatowanie, 16
D
dane, 64, 155
globalne, 34
na wyjciu, 155
najmniejszy typ, 189
oznaczanie koca, 77
statyczne, 54
struktura, 8, 39, 59
szkodliwe, 164
typ le dobrany, 128
wejciowe, 187
wybór struktur, 89
wyjciowe, 187
wymiana, 209, 212
Date, 178
debugging, 125
debugowanie, 126, 256
decyzje
wielokierunkowe, 25
defensive programming, 122
defensywne programowanie, 122, 151
definicja,
pakietów, 202
pola, 99
dekrementacja, 19
deque, 84
design patterns, 91
deskryptywna
nazwa, 13
destruktor, 116
diagnostyka
bdów, 127
instrukcji, 127
kodu, 9
programu, 126, 140
diff, 135
Dijkstra, 147
dugo sów, 85
dobry
interfejs, 112
kod, 37
technika sortowania, 63
zestaw testów, 161
domylny rozmiar tablicy, 73
dowiadczenia, 253
double, 187
do-while, 23
drukowanie elementów listy, 56
drzewo, 59
analiza skadniowa, 63
korze, 59
niezrównowaone, 61
poszukiwa binarne, 59, 60
przegldanie poprzeczne, 62
zrównowaone, 61
dublowanie elementów, 61
dwuznacznoci unikanie, 16
dzieci wze, 60
dzielenie, 59
dziennik
bd, 134
E
efekty uboczne, 19
efektywno wykorzystania pamici, 190
elastyczno, 108
element
dostp swobodny, 59
dublowanie, 61
grupowanie, 16
liczenie, 57
o zmiennym rozmiarze, 59
powizany, 14, 64
przesuwanie, 53
wstawianie, 59
else, 25, 26
else-if, 25, 26
Ellis, 89
endian, 218
endprintf, 117
enum, 31
EOF, 200
estrdup, 118
ewaluacja, 19, 29
exception, 120
F
fall-through, 26
fclose, 151
fflush, 134
fgets, 24, 148
filtr spamu, 176
final, 31
find, 40
Flandren, 194
float, 187
flush, 134
flushcaches, 249
fopen, 151
for, 22, 23
262
SKOROWIDZ
format
CSV, 94, 95, 96
ptla, 22
formatowanie
czytelne, 16
wyraenia, 16
fprintf, 151
fragment niejasny, 11
fread, 151
free, 192
funkcja
generujca, 81
komentarz, 34
logiczna, 14
acuchowa, 114
mieszajca, 64, 67, 74, 75
nazwa, 13, 14
sortujca, 44
fwrite, 151
G
garbage collection, 116
generate, 242
generator
liczb losowych, 49
odsyaczy, 143
tekstu, 77
getchar, 23, 28
gets, 24, 164
getTime, 178
GIF, 190
globalne
dane, 34
optymalizator, 182
zmiennne, 112
gowa, 54
gówny nurt jzyka, 197
gorcy punkt, 178, 184, 186
graficzne operacje, 188
gramatyka, 238
granice tabeli, 166
grep, 143, 172, 229, 234
grupowanie elementów, 16
H
Hashtable, 79, 83
head, 54
hermetyzacja, 112
hierarchiczna struktura danych, 59
Hoare, 42, 47
I
IBM 7094, 248
idealny komentarz, 33
idiom, 22, 24
idiomatyczny kod, 36
if, 20, 21, 25
if...else, 19, 25
implementacja,
niezalene wyniki, 156
programu, 8
indeksowania operator, 85
indexOf, 40
Inferno, 187
informacja
o bdzie, 151
ukrywanie, 99, 100, 112
inicjalizacja, 114
statyczna, 115
tablica, 167
zmienna, 167
inkrementacja, 16, 19
in-order traversal, 62
insert, 62
instrukcja, 16
diagnostyczna, 127
sprawdzajca, 26
Integer, 48
interaktywnego programu test, 168
interfejs, 8, 47, 96, 99, 112, 208, 254, 256
CSV, 112
do tablic rozproszonych, 64
dobry, 112
duy, 113
atwy w uyciu, 123
poprawny, 150
programistyczny, 113
publiczny, 80, 108
uytkownika, 9, 121
zasady tworzenia, 112
zwizy, 113
internacjonalizacja, 216
internationalization, 216
internetowy robak, 165
interpreter, 237
polece, 234
isspam, 179
isupper, 28
J
jasny algorytm, 86
Java, 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, 242
jednokierunkowa lista, 54
SKOROWIDZ
263
jednolito, 123
jzyk
may, 222
niskiego poziomu, 9, 188
nurt gówny, 197
programowania, 9
skryptowy, 236
standard, 196
wybór, 221
wysokiego poziomu, 9
JIT, 247
just in time compilation, 247
JVM, 242
K
klamry, 27
klarowno, 26, 253
klasa, 201
globalna, 13
kontenerowa, 79
klucze, 64
Knuth, 167, 178, 194
kod
diagnostyka, 9
dobry, 37
generowanie za pomoc makr, 246
idiomatyczny, 36
klarowny, 19, 36
atwo czytania, 12
nizany, 240
optymalizacja, 182
pokrycie testami, 156
przejrzysty, 18
regulacja, 183
samosprawdzajcy, 133
spójny, 12
sprytny, 18
struktura, 16
uwypuklenie, 20
testowanie w czasie pisania, 151
wolny od bdów, 147
wyszej jakoci, 151
zaleny od maszyny, 188
zwizy, 19, 86
ródowy, 12
Koenig, 245
kolejka, 14
dwukierunkowa, 84
kolejno,
bajtów, 201
wykonywania oblicze, 199
kolizja, 67
komentarz, 33, 34
aktualizacja, 35
cel stosowania, 37
funkcja, 34
idealny, 33
niejasny, 37
kompilacja
na czas, 247
w locie, 247
warunkowa, 205
kompilator, 166, 182, 184, 195, 197, 243, 250
bd, 143
optymalizacji kodu, 182
testowanie, 155, 201
komputer zasady korzystania, 7
komunikat, 217
o bdzie, 118
konflikt nazw, 113
konstruktor, 115, 116
kontener, 83
konwencje, 12
konwersji wspóczynnik, 29
kocowy warunek, 149
kopiowanie, 59, 114
korze drzewa, 59
kosztów model, 191
krotka, 120
kubeek, 64
L
last-in-first-out, 59
liczba, 29, 31
0, 31
cakowita, 45, 191
double, 128
losowa, 49
zmiennoprzecinkowa, 191
liczenie elementów, 57
licznik odniesie, 116
LIFO, 59
liniowe przeszukiwanie, 40
lista, 54, 83
drukowanie elementów, 56
jednokierunkowa, 54
modyfikacja, 55
pami wolna, 186
tworzenie, 55
usuwanie, 57, 58
li, 61
literate programming, 245
little languages, 222
locality, 186
Locanthi, 246
logiczne przesunicie, 200
lokalnoci zasada, 186
lookup, 62
losowa liczba, 49
264
SKOROWIDZ
acuch
algorytm tworzenia, 166
nazwa, 13
Markowa , 70, 79
acuchowa funkcja, 114
atwy w uyciu interfejs, 123
M
mainstream, 197
makro, 28, 31, 32
argumenty, 29
generowanie kodu, 246
problem, 28
malloc, 24, 129, 192
mae jzyki, 222
map, 79, 84, 85
markov, 70, 91, 163, 170
maszyna,
stosowa, 240
wirtualna, 237
Math.abs, 49
mechanizm wyjtków, 120
memcmp, 179, 183
memcopy, 53
memcpy, 113
memmove, 53, 113, 188
memset, 161, 188
metacharacters, 228
metaznaki, 228
Microsoft Visual C++ 5.0, 163
mierzenie czasu, 172, 177
mieszajca funkcja, 74
Mitchell, 89
mocy zmniejszenie, 184
model,
kosztów, 191
statystyczny tekstu, 70
Modula-3, 243
modularyzacja, 112
N
nadmiarowa kontrola cykliczna, 67
najmniejsze typy danych, 189
najprostsza struktura danych, 53
najwspanialsze osignicie informatyki, 64
Nameval, 51
NaN, 120
nawiasy, 16
klamrowe, 20
nazwa, 13
deskryptywna, 13
elementy powizane, 14
funkcja, 14
logiczna, 14
klasa globalna, 13
konflikt, 113
acuch, 13
niespójna, 14
prywatna, 113
staa, 13
struktura globalna, 13
wskanik, 13
zmienna,
globalna, 13
lokalna, 13
ptlowa, 13
negacja, 35
new, 129
niedorzeczne wartoci, 128
niejasny
fragment, 11
komentarz, 37
niepoprawne dane wejciowe, 122
nieprzezroczysty typ, 112
niesychanie dua warto, 128
niespójna nazwa, 14
nietypowe sytuacje, 120
niezalene implementacje, 156
niezamykanie plików, 138
niezrównowaone drzewo, 61
niskopoziomowy jzyk, 9
nizany kod, 240
not a number, 120
notacja, 221, 254
O, 50
programowanie, 9
nowy wze, 61
null, 32
numerycznego programu test, 155
nurt gówny jzyka, 197
nvcmp, 46
O
obcieniowe testy, 9
obiektu rozmiar, 32
Object, 47, 48
obliczenia
kolejno wykonywania, 199
zawczasu, 187
obsuga bdów, 99, 101, 117
zasada, 119
oczekiwana zoono algorytmu, 50
odsyaczy generator, 143
odzyskiwanie zasobów, 116
ogonowa rekurencja, 62
ogólno, 253
programowania, 7
SKOROWIDZ
265
on the fly compilation, 247
O-notation, 50
operacja
graficzna, 188
wejcia, 19
wyjcia, 19
operator, 16
bitowy, 17
indeksowania, 85
logiczny, 17
priorytet, 17
przecianie, 189
przypisania, 17
relacji, 17, 24
opónienia w dostarczaniu poczty, 172
optymalizacja, 184, 193
gospodarowania pamici, 189
kodu kompilatora, 182
wykorzystania zasobów, 9
zasada, 171
optymalizator globalny, 182
oszczdzanie pamici, 190
oznaczanie koca danych, 77
P
pair, 120
pakietów definicja, 202
pami, 114
alokowanie, 24, 166, 186, 192
efektywno wykorzystania, 190
optymalne gospodarowanie, 189
oszczdzanie, 190
podrczna, 186
wolna, 186
wyciek, 138
zwalnianie, 192
Pathfinder, 130
Perl, 9, 86, 87, 90, 237
pesymistyczna zoono algorytmu, 50
ptla, 16, 21, 22, 23, 24, 148
eliminacja, 185
format, 22
pierwsze wystpienie znaku, 40
pisanie kodu, 151
pimienne programowanie, 245
plik
dziennika, 134
nagówkowy, 202
niezamykanie, 138
poczty opónienia w dostarczaniu, 172
podrczna pami, 186
podstawowe algorytmy, 39, 83
pole
bitowe, 201
definicja, 99
pomiary, 193
wykonywanie, 172
poprawa wydajnoci, 175
poprawno interfejsu, 150
porównywanie
czasu dziaania algorytmów, 50
liczb cakowitych, 45
portability, 195
Portable Operating System Interface, 218
porzdek bajtów, 211
POSIX, 204, 218
post-order traversal, 63
PostScript, 245
potok, 249
potomek, 60, 61
powizane elementy, 64
pozycja znaku, 29
PPM, 190
praktyka programowania, 7, 12
Prefix, 81, 82
pre-order traversal, 63
printf, 97, 128, 222
priorytetu operator, 17
problemu rozmiar, 50
procedura przeszukujca, 40
procesor, 195
prof, 178
profil, 172, 173, 178
program
diagnostyczny, 126, 140
wady, 127
zalety, 126
do powszechnego uytku, 90
generujcy tekst, 69
graficzny, 155
implementacja, 8
interaktywny, 168
jak napisa, 12
numeryczny, 155
odporny na niepoprawne dane wejciowe, 122
pisze programy, 242
profilujcy, 172, 173,178
prototyp, 98
przekazanie do uytku, 166
przenony, 9, 195
przyspieszanie dziaania, 183
rzeczywiste dziaanie, 137
spowolnienie, 189
struktura, 143
wamanie, 164
wydajno, 88, 188
zoono obliczeniowa, 181
programowanie
defensywne, 122, 151
notacja, 9
ogólno, 7
266
SKOROWIDZ
programowanie
pimienne, 245
praktyka, 7, 12
prostota, 7
przejrzysto, 7
styl, 8, 38
zasady, 12
projektu analiza, 8
prostota programowania, 7, 253
prototyp, 197
programu, 98
prywatna nazwa, 113
przechowywanie elementów o zmiennym rozmiarze, 59
przecianie operatorów, 189
przegldanie
poprzeczne, 62
wsteczne, 63
wzdune, 63
przejrzysto, 13
programowanie, 7
przekazanie programu do uytku, 166
przenono programów, 9, 142, 195, 214, 257
przepenienie, 46
bufora, 164
przesunicie
arytmetyczne, 200
elementu, 53
logiczne, 200
przeszukiwanie
binarne, 41, 46
liniowe, 40
procedura, 40
sekwencyjne, 40
tablicy, 154
tekstu, 143
przydzielanie pamici, 114
przypisanie, 16
operator, 17
wstawianie do warunku ptli, 23
przyspieszanie
algorytmu, 181
dziaania programu, 174, 183
struktury danych, 181
publiczny interfejs, 80, 108
puapki jzykowe, 198
punkt gorcy, 184, 186
putchar, 23
Q
qsort, 44, 45, 46
queue, 14
quicksort, 42, 49
R
rama testowa, 154, 159, 162, 193
rand, 49
RCS, 135
real, 177
realloc, 129
reduction in strength, 184
reentrant, 116
reference count, 116
referencja, 115
regression testing, 157
regresywne testowanie, 157, 180, 184
regulacja kodu, 183
regular expressions, 228
regularne wyraenia, 228
rekurencja, 47
ogonowa, 62
relacji operator, 17, 24
reputacji utrata, 143
rgen, 49
robak internetowy, 165
rozmiar
bufora, 76
obiektu, 32
problemu, 50
tablicy, 29, 33, 66, 104
typów danych, 198
rozszerzalna tablica, 51
rozwój, 253
rzutowanie, 53
S
samodzielne testy, 158
samosprawdzajcy si kod, 133
scalanie, 59
scanf, 96, 128, 151
scmp, 45
sekwencyjne wyszukiwanie, 40
sentinel, 77
shaney, 91
sizeof, 32
skadni bdy, 21
skrócenie czasu usuwania usterek, 125
skrypt testowy, 158
skryptowy jzyk, 236
sowa, 73, 85
sownik, 84, 87
struktura danych, 79
sort, 47, 49
sortowanie
algorytm, 42, 47
dobra technika, 63
funkcja, 44
szybkie, 42
tablic acuchów, 45
SKOROWIDZ
267
spam, 172
filtr, 176
specyfikacja, 101
zawarto, 101
split, 103, 105, 109
sposoby doboru testów, 154
spójno, 20, 22, 114
kodu, 12
zewntrzna, 114
sprztu bd, 138
staa, 19, 31
cakowitoliczbowa, 31
nazwa, 13
znakowa, 31
stanu utrzymywanie, 114
standard, 197, 202
ANSI C, 24, 202, 222, 225
ANSI/ISO jzyka C, 196
ISO jzyka C++, 196
jzyka, 196
Standard Template Library, 83
State, 73
statyczna inicjalizacja, 115
statyczne dane, 54
stderr, 134
stdout, 113
STL, 59, 83, 90, 120, 163
stos, 59, 186
wywoa, 126, 130
strchr, 40, 179
strcmp, 36, 45
strcpy, 24
strdup, 24
StreamTokenizer, 80
strerror, 120
String, 40, 48
strings, 140
strlen, 24, 179
strncmp, 179
stronicowanie, 189
strstr, 40, 173, 176, 179
strtok, 96, 105, 113
struktura
danych, 8, 39, 201
najprostsza, 53
sownik, 79
globalna nazwa, 13
kodu, 16
programu, 143
strumienie bdów, 134
styl, 12, 255
funkcja, 12
programowania, 8, 38
swap, 49
Swift, 218
swobodny dostp do elementów, 59
symbole,
tablica, 64
wieloznaczne, 228
SYS, 177
system
zalenoci, 208
operacyjny, 195
System.err, 134
systematyczne testowanie niewielkich przypadków, 154
sytuacje nietypowe, 120
szkodliwe dane wejciowe, 164
szybkie sortowanie, 42
T
tabela
granice, 166
tablica, 40, 53
asocjacyjna, 86
domylny rozmiar, 73
inicjalizacja, 167
acuchów, 45
mieszajca, 51, 64, 80
funkcja tworzca, 75
przeszukanie, 154
rozmiar, 29, 33, 66, 104
rozproszona, 64
rozszerzalna, 51
sowa, 73
symboli, 64
znaków, 108
tail recursion, 62
Tcl/Tk, 9
technika usuwania bdów, 125
tekst
algorytm tworzenia, 85
generowanie, 77
model statystyczny, 70
przeszukiwanie, 143
test, 9, 147, 153, 193, 256
algorytm Markowa, 168
automatyzacja, 157
biaej skrzynki, 167
cel, 167
czarnej skrzynki, 167
dobry zestaw, 161
dua iloci danych, 163
kompilator, 155
obcieniowy, 9
pokrycia kodu, 156
programu,
graficznego, 155
interaktywnego, 168
numerycznego, 155
przecieniowy, 163
rama, 154, 159, 162
268
SKOROWIDZ
test
regresywny, 157, 180, 184
samodzielny, 158
sposoby doboru, 154
stopniowy, 153
systematyczny, 153
testu, 168
ustawienia parametrów wejciowych, 167
w czasie pisania kodu, 151
wartoci brzegowych, 9, 148
rozszerzenie metody, 154
wzorcowy, 194
zautomatyzowanie, 154
zestaw, 153, 167, 174
TEX, 167
Thompson, 194, 248
threaded code, 240
time, 177
tuple, 120
tworzenie listy, 55
typ danych
najmniejszych, 189
nieprzezroczysty, 112
rozmiar, 198
le dobrany, 128
U
uboczne efekty, 19
ukrywanie informacji, 99, 100, 112
unia, 201
Unicode, 216
unikanie dwuznaczno, 16
unquote, 96
unsigned char, 66
ustawianie wartoci pocztkowych, 115
usterki czas usuwania, 125
usuwanie
bdów, 147
listy, 57, 58
usterek, 125
UTF-8, 217
utrata reputacji, 143
utrzymywanie stanu, 114
uytkownika interfejs, 9, 121
V
Vector, 79, 83, 84, 108
Visual Basic, 9, 243
void*, 44, 53
W
wartoci
bezwzgldne, 49
brzegowych testowanie, 9
niedorzeczne, 128
niesychanie due, 128
oddzielane przecinkami, 94
pocztkowych ustawianie, 115
zmiennej modyfikacja, 19
wartownik, 77
warunek, 25
brzegowy, 148
kocowy, 149
ptli, 23
wstpny, 149
warunkowa,
kompilacja, 205
wyraenie, 19
wcicia, 16, 20, 21
wczytywanie liczb typu double, 128
wejcie, 19
wektor, 83
weprintf, 61, 117
wersja beta, 168
wze
dzieci, 60
nowy, 61
while, 23, 26
wielokierunkowe decyzje, 25
wielowejciowy program, 116
wildcards, 228
wiszcy wskanik, 139
wamanie do programu, 164
waciwoci danych wejciowych, 155
wprintf, 203
wskanik
brakujcego potomka, 60
nazwy, 13
wiszcy, 139
wspóczynnik konwersji, 29
wspódzielenie, 114
wstawianie elementu, 59
wsteczna zgodno, 215
wstpny warunek, 149
wybór
algorytmu, 68, 182
jzyka, 9, 221
struktur danych, 89
wycieki pamici, 138
wydajno, 171, 257
analiza graficzna, 180
poprawa, 175
program, 88, 188
wyjtek, 120
wyjcie, 19
SKOROWIDZ
269
wykadnicza zoono obliczeniowa, 51
wykonywanie pomiarów, 172
wykorzystania zasobów optymalizacja, 9
wykres bdów, 134
wykrywanie bdów, 9
wymagania pamiciowe algorytmu, 50
wymiana danych, 209, 212
wyniki niezalenych implementacji, 156
wyraenia, 16
formatowanie, 16
regularne, 228
skomplikowane, 17
warunkowe, 19
wysokiego poziomu jzyk, 9
wyszukiwanie
binarne, 42
sekwencyjne, 40
wywoanie
stos, 126, 130
wzorzec projektowy, 91
Y
Yorktown, 150, 151
Z
zalenoci systemowe, 208
zarzdzanie zasobami, 58, 99, 100, 114
zasada
korzystania z komputera, 7
lokalnoci, 186
obsugi bdów, 119
optymalizacji, 171
programowania, 12
zasoby
odzyskiwanie, 116
zarzdzanie, 58, 99, 100, 114
zautomatyzowanie testowania, 154
zbiór, 83
klas kontenerowych, 79
zero, 31
zestaw
testów, 153, 167, 174
znaków, 216
zewntrzna spójno, 114
zgodno wsteczna, 215
zoono obliczeniowa, 50, 56, 181
wykadnicza, 51
zmienna, 103
globalna, 13, 112
inicjalizacja, 167
lokalna, 13
modyfikacja wartoci, 19
nazwa, 13
ptlowa, 13
wewntrzna, 103
zmniejszenie mocy, 184
znak
pierwsze wystpienie, 40
pozycja, 29
tablica, 108
zapytania, 12
zestaw, 216
zrównowaone drzewo, 61
zwalnianie pamieci, 114, 192
zwikszenie wydajnoci programu, 188
zwizo, 13
kodu, 86