VIII. Wyszukiwanie błędów
Środowisko Visual Studio 2010 integruje narzędzia pozwalające programiście efektywnie pro-
jektować aplikację. Wcześniejsze ćwiczenia wykorzystywały edytor i kompilator w celu uzyskania
działającej aplikacji. Edytor, kontrolując w sposób ciągły wprowadzany kod źródłowy, pozwala progra-
miście skupić się na implementowaniu pomysłów. „Pomocna dłoń” edytora przejawia się w wielu
aspektach. Po pierwsze, dla wybranego typu projektu tworzy on standardowe pliki kodu źródłowego.
Przykładem tego działania jest plik zawierający procedurę Main. Inny rodzaj wspomagania polega na
uzupełnianiu kodu źródłowego elementami, które muszą wystąpić ze względu na wymagania składni
języka. Przypomnijmy w tym miejscu słowa kluczowe
End Sub
(
End Function
) dodawane przez
edytor w chwili tworzenia nowego wiersza (naciśnięcia klawisza Enter) po zakończeniu wprowadza-
nia nagłówka procedury (funkcji), ponadto edytor uzupełnia deklaracje parametrów o słowo kluczowe
ByVal
. Edytor udziela także podpowiedzi na temat wskazanego elementu kodu źródłowego. Progra-
miści pracujący w różnych językach programowania z pewnością doceniają tworzenie przez edytor
wielu konstrukcji po wpisaniu charakterystycznego słowa kluczowego i dwukrotnym naciśnięciu tabu-
latora.
Do najprostszych błędów popełnianych w trakcie pisania kodu źródłowego należą tzw. literówki.
Błędy tego typu wychwytuje edytor tekstowy. Polega to na ciągłym porównywaniu wpisywanych przez
programistę słów z zadeklarowanymi wcześniej typami, zmiennymi, funkcjami itp. elementami środo-
wiska. Jeśli dany ciąg znaków nie został wcześniej zadeklarowany, innymi słowy jest nieznany
dla środowiska, to zostanie on podkreślony falowaną, niebieską linią. Podkreślenie służy w ogólności
do wskazywania błędów składniowych języka. Zaliczają się do nich np. użycie zmiennych, które nie
zostały wcześniej zadeklarowane, pominięcie wymaganego elementu deklaracji, użycie niedozwolo-
nych w kodzie źródłowym znaków.
Kolejne ćwiczenie przypomina wybrane działania edytora wspomagające programistę.
Ćwiczenie 95
Zaobserwować wspomagające działania edytora kodu źródłowego.
1. Utwórz projekt aplikacji konsolowej.
2. Zdefiniuj w części deklaracyjnej modułu enumerację RodzajOpisu. Zauważ, że po wpisa-
niu słów Enum RodzajOpisu i naciśnięciu klawisza Enter pojawia się wprawdzie komplet-
ny blok struktury, ale nazwa RodzajOpisu jest podkreślone niebieską, falowaną linią.
3. Naprowadź kursor myszy na podkreślone słowo i zapoznaj się z podpowiedzią.
Przykład.
Podpowiedź wskazuje na konieczność umieszczenia chociaż jednego elementu w bloku enu-
meracji. Warto zwracać uwagę na wszelkie podpowiedzi zawierające słowo must – musieć.
4. Wyświetl okno Error List (Lista błędów) wybierając menu View, a następnie polecenie Er-
ror List. Okno można również aktywować używając myszy (jeśli jest wyświetlane) klikając
zakładkę Error List, lub sekwencją Ctrl+W, Ctrl+E (przy wciśniętym klawiszu Ctrl należy
wcisnąć kolejno klawisz W i (po zwolnieniu W) klawisz E.
Przykład. Nieaktywna zakładka Error List po nieudanej próbie kompilacji Projekt_103.
5. Zwróć uwagę na pierwszą linię tekstu w kolumnie Description (Opis), zawiera ona widzia-
ną wcześniej podpowiedź, ta jest jednak statyczna, co pozwala wykonywać inne czynno-
ści myszą.
Przykład.
6. Kliknij dwukrotnie opis błędu w oknie Error List:
•
w kodzie źródłowym zaznaczone zostało niebieskim tłem słowo Historia, „po-
strzegane” przez edytor jako miejsce wystąpienia błędu,
•
w pasku stanu środowiska widnieje opis błędu.
Przykład.
7. Dodaj w deklaracji struktury stałe Krótki oraz Długi. Zauważ, że zniknęło podkreślenie
słowa RodzajOpisu oraz wpis w oknie Error List. Gdy środowisko wykona inne zadanie,
komunikat paska stanu zostanie zastąpiony komunikatem o innym błędzie, lub braku błę-
dów i gotowości środowiska – Ready.
Właściwość środowiska omówiona w ćwiczeniu 95. stanowi wspaniały dodatek ułatwiający pra-
cę programistom niezależnie od stopnia zaawansowania ich umiejętności. Możliwość skupienia się
wyłącznie na rozwiązywanym zadaniu, a pozostawienie mozolnego wykrywania błędów składni śro-
dowisku, stanowi o wielkiej użyteczności Visual Studio 2010.
Innym zabezpieczeniem przed błędami popełnianymi w kodzie źródłowym jest polecenie Com-
pleteWord (Uzupełnij słowo). Jest to polecenie edycyjne. Służy do uzupełniania wpisywanych
do kodu źródłowego słów. Jeśli programista wpisze dość liter, aby edytor mógł zidentyfikować jedno-
znacznie wpisywane słowo, to zostanie ono uzupełnione. Jeśli ilość liter jest niewystarczająca do peł-
nej identyfikacji, to edytor wyświetli listę słów, z której można wybrać pasujące.
Kolejne ćwiczenie ugruntowuje znajomość z oknem Error List oraz zapoznaje z poleceniem
CompleteWord.
Ćwiczenie 96
Zapoznać się z różnymi wariantami działania polecenia CompleteWord.
1. Rozpocznij deklarowanie w procedurze Main zmiennej DługośćOpisu wpisując: Dim Dłu-
gośćOpisu As.
2. Dopisz spację i zauważ, że edytor w miejscu położenia kursora tekstowego rozwija listę
pasujących do kontekstu elementów języka.
Przykład.
3. Zamknij listę naciskając klawisz Esc.
4. Wpisz literę R i uruchom polecenie CompleteWord wybierając sekwencję Ctrl+Spacja –
edytor ponownie rozwija, posortowaną alfabetycznie, listę elementów pasujących do kon-
tekstu, tym razem zaznaczając pierwsze słowo rozpoczynające się od litery R.
Przykład.
5. Zamknij listę naciskając klawisz Esc.
6. Dopisz (świadomie popełniając błąd) literę b tak, aby wprowadzany tekst rozpoczynał się
od liter Rb.
7. Uruchom ponownie polecenie CompleteWord. Jeśli żaden pasujący do kontekstu ele-
ment nie rozpoczyna się od liter Rb, to edytor nie dokona wyboru (cieniowane tło), za-
znaczy jedynie pierwsze słowo rozpoczynające się od litery R.
Przykład.
8. Usuń dopisaną literę y używając klawisza Backspace, edytor ponownie wyświetla listę
tak, jak w punkcie 4.
9. Dopisz literę o, na liście zaznaczony zostaje element RodzajOpisu. Zatwierdź wybór kla-
wiszem Enter. (Wybór można również zakończyć klawiszem spacji, co w wielu przypad-
kach jest lepszym rozwiązaniem – nie tworzy nowego wiersza kodu źródłowego, albo
klawiszem tabulacji – należy jednak pamiętać, że dwukrotne naciśnięcie klawisza tabula-
cji powoduje wstawienie do kodu schematu (jeśli istnieje) wprowadzanej konstrukcji,
np. For, If, While, Do itd.)
10.Usuń z nazwy RodzajOpisu ciąg znaków zajOpisu i uruchom polecenie CompleteWord.
Ponieważ inna nazwa nie rozpoczyna się od liter Rod, to edytor automatycznie wybiera
jedyny pasujący element listy i uzupełnia nazwę.
Polecenie CompleteWord zwalnia programistę z obowiązku zapamiętywania pełnych nazw defi-
niowanych typów, deklarowanych zmiennych itp. Wystarczy pamiętać początkowe znaki nazw, resztą
zajmie się edytor.
Konieczna jest w tym miejscu uwaga przypominająca o konsekwentnym stosowaniu metodyki
tworzenia nazw. Programista stosujący przedrostki wskazujące na typ zmiennej ułatwia sobie odnale-
zienie zmiennej na liście elementów wyświetlanych w wyniku uruchomienia polecenia Complete-
Word.
Polecenie można uruchomić w każdym miejscu kodu źródłowego. W pewnych przypadkach li-
sta rozwija się automatycznie, bez udziału programisty, np. po słowie As i spacji, po kropce, gdy od-
wołujemy się do pól zmiennej strukturalnej.
Dotychczasowy kod projektu jest stosunkowo krótki, dlatego łatwo można w nim zauważyć błę-
dy wykryte przez edytor. Biorąc pod uwagę fakt, że projekty z reguły bywają bardziej rozbudowane, a
także to, że programista może otrzymać fragmenty kodu zawierające błędy, można dojść do wniosku,
że czasami wyśledzenie pomyłki może okazać się trudne, zwłaszcza jeśli okno Error List nie jest wi-
doczne. Kolejne ćwiczenie ma na celu zobrazowanie takiej sytuacji.
Ćwiczenie 97
Zapoznać się z komunikatami generowanymi na etapie kompilacji projektu.
1. Dołącz do projektu moduł Moje_095 dostarczony wraz z treścią ćwiczeń.
2. Zadeklaruj zmienną Dane typu Historia, posłuży do przechowywania jednego zestawu
danych. Typ strukturalny Historia jest zdefiniowany w module Moje_095.
3. Zadeklaruj tablicę hiObliczenia o dziesięciu komórkach (najwyższy indeks to 9) typu Hi-
storia.
4. Zadeklaruj zmienną intIleZestawów typu Integer o wartości początkowej równej 0, posłu-
ży do przechowywania liczby zestawów danych pobranych od użytkownika.
5. Skonstruuj pętlę Do z warunkiem sprawdzanym na końcu. Pętla powinna być wykonywa-
na tak długo, jak długo wynik funkcji Wybór wynosi „T”. Funkcja Wybór jest zdefiniowana
w module Moje_095.
6. Utwórz w pętli konstrukcję wiążącą With dla zmiennej Dane i zaprogramuj w niej:
•
wykorzystanie procedury Pobierz do pobrania dwóch wartości do pól Dzielna i Dzielnik,
•
obliczenie wyniku dzielenia wartości pól Dzielna i Dzielnik i przypisanie go do pola Iloraz,
•
wyświetlenie danych oraz wyniku w formacie pokazanym na rysunku przedstawiającym
efekt pracy aplikacji (patrz: rys. 47). Wykorzystaj funkcję Wyrównaj (moduł Moje_095).
7. Zaprogramuj po konstrukcji wiążącej With zwiększenie wartości zmiennej intIleZestawów
o jedność.
8. Utwórz konstrukcję warunkową sprawdzającą czy wartość zmiennej intIleZestawów jest
mniejsza niż 11. Jeżeli warunek jest spełniony, to wartość zmiennej Dane powinna zostać
przypisana odpowiedniej komórce tabeli hiObliczenia.
Przykład.
hiObliczenia(intIleZestawów – 1) = Dane
9. Zaprogramuj po pętli Do wywołanie procedury WyświetlHistorię (moduł Moje_095) prze-
kazując jako parametr tablicę hiObliczenia i zmienną intIleZestawów.
10.Spróbuj uruchomić aplikację i zapoznaj się z komunikatem środowiska o postaci:
11. Przerwij kompilację wybierając No.
12.Zapoznaj się z wpisami okna Error List.
Przykład.
13.Znajdź miejsce wystąpienia błędu (dwukrotne kliknięcie we wpis) i napraw go usuwając
apostrof rozpoczynający komentarz z deklaracją zmiennej Tekst.
Efekt działania programu może być taki jak przedstawiono na rysunku:
Kod źródłowy projektu nie był w tym ćwiczeniu najważniejszy, dlatego poniżej przedstawiono
jedną z możliwych wersji procedury Main w module startowym projektu:
W punkcie 10. ćwiczenia próbowaliśmy uruchomić aplikację. Program tłumaczący kod źródłowy
na kod wykonywalny zakomunikował, że podczas translacji odnalezione zostały błędy. Mówi o tym
treść okna Microsoft Visual Studio – There were build errors. Komunikat kończy się pytaniem, czy
kontynuować próbę uruchomienia. Do wyboru mamy jedną z dwóch możliwości – przerwać urucha-
mianie (przycisk No), lub kontynuować (przycisk Yes). Przerywając uruchamianie powodujemy po-
wrót do projektowania. Jeżeli potwierdzimy chęć kontynuacji uruchamiania, to zostanie uruchomiona
ostatnia pozbawiona błędów kompilacja. Jest to szczególnie ważne dla początkujących programistów
– aplikacja nie działa „mimo błędów”, jak to słyszy się niejednokrotnie – uruchomiona aplikacja, to po
Rysunek 47: Projekt_103 w działaniu.
prostu efekt działania poprzedniej, pozbawionej błędów, wersji projektu. Kolejne ćwiczenie pokazuje
istotność powyższych zdań.
Ćwiczenie 98
Dokonać próby uruchomienia aplikacji projektu, który nie posiada wcześniejszej,
pozbawionej błędów, skompilowanej wersji.
1. Utwórz projekt aplikacji konsolowej.
2. Przypisz w procedurze Main zmiennej intLiczbaPrób (nie należy deklarować tej zmiennej,
chodzi o popełnienie oczywistego błędu) wartość 7.
3. Dokonaj próby uruchomienia aplikacji.
4. Potwierdź chęć kontynuacji mimo wykrytych błędów.
5. Zapoznaj się z komunikatem okna Microsoft Visual Studio.
Przykład. Obserwowana przez ćwiczących treść komunikatu może być odmienna – inna będzie
ścieżka dostępu.
W komunikacie okna Microsoft Development Environment czytamy:
Visual Studio nie może rozpocząć debugowania ponieważ brakuje podmiotu debugowania (tu
występuje ścieżka dostępu do pliku wykonywalnego). Proszę skompilować projekt i ponowić próbę.
Skompilowane projekty są przechowywane w folderze o nazwie Debug. Jeśli żadna kompilacja
nie zakończyła się powodzeniem, ze względu na błędy w kodzie źródłowym, to folder ten nie zawiera
pliku wykonywalnego.
Ostatni punkt ćwiczenia 97. polegał na usunięciu błędu uniemożliwiającego kompilację. Projekt
został skompilowany i można uruchomić aplikację. Czy oznacza to, że aplikacja będzie działać po-
prawnie?
Odpowiedź nie jest jednoznaczna. Może się tak zdarzyć, że w czasie pracy aplikacji nie wystą-
pią błędy (zostały podane dwa zestawy danych i program działał poprawnie). Jednak istnieje prawdo-
podobieństwo, że zbudowany przez nas projekt, wobec splotu różnych okoliczności – szczególny ze-
staw danych, błąd logiczny w implementacji algorytmu, błędny algorytm itd., będzie generował błędne
wyniki lub będzie pracował nieprzewidywalnie, albo też będzie przerywał działanie. Usuwanie takich
błędów możliwe jest jedynie wtedy, gdy znamy miejsce i przyczynę ich wystąpienia. Pierwotnym za-
gadnieniem jest odnalezienie w kodzie źródłowym miejsca zawierającego instrukcję, której wykona-
nie kończy się błędem. Niestety, często jest to dopiero początek żmudnej drogi odszukiwania pier-
wotnego źródła błędu. Na każdym kroku działania programisty w tym zakresie wspiera debugger –
narzędzie śledzące powiązanie wykonywanej instrukcji kodu wykonywalnego z kodem źródłowym.
Aby wykorzystać to narzędzie należy uruchamiać aplikację projektu używając debuggera. Kolejne
ćwiczenie rozpoczyna serię dotyczącą błędów czasu wykonania, czyli takich, które pojawiają się już
w trakcie działania aplikacji.
Ćwiczenie 99
Zapoznać się z błędami czasu wykonania.
1. Uruchom aplikację projektu utworzonego w ćwiczeniu 95. włączając mechanizm debug-
gera Visual Studio 2010, w tym celu rozwiń menu Debug i zapoznaj się z występującymi
w nim grupami poleceń, zwróć uwagę na polecenie Start Debugging – F5, włącza ono
debugowanie. Zwróć uwagę na ikonę polecenia, występuje ona w pasku narzędzi De-
bug.
2. Wprowadź jako pierwszą dzielną dowolną liczbę, a jako pierwszy dzielnik tekst: Duża
liczba.
3. Zauważ, że działanie aplikacji zostało wstrzymane, uaktywnione zostało okno Visual Stu-
dio 2010 z tym fragmentem kodu źródłowego, w którym nastąpił błąd podczas pracy apli-
kacji. Linia z poleceniem, które zakończyło się błędem jest wyróżniona zmienionym kolo-
rem tła oraz strzałką na lewym marginesie okna. Dodatkowo wyświetlone jest okno z opi-
sem błędu.
4. Zapoznaj się z treścią okna z opisem błędu.
Przykład.
5. Zamknij okno ostrzeżenia.
6. Zakończ aplikację wybierając polecenie Stop Debugging z menu Debug.
Objaśniając słowo „debugowanie” można napisać, że oznacza ono czynność polegającą na
usuwaniu błędów. Rozpoczyna się od momentu uruchomienia procesu poleceniem Start z menu De-
bug, a kończy w chwili zakończenia aplikacji, lub po wybraniu polecenia Stop Debugging.
Wróćmy do objaśnienia reakcji środowiska. Aplikacja pobrała z konsoli ciąg znaków „Duża licz-
ba”, dalej nastąpiła próba konwersji tego tekstu na liczbę rzeczywistą. Próba ta zakończyła się niepo-
wodzeniem. Program debugujący zgłosił ten problem, komunikując, że wyjątek typu
InvalidCastE-
xception
nie został obsłużony, a także dodał informacje, że „Konwersja ciagu „Duża liczba” na typ
'Double' nie jest dozwolone”.
Informacja dodatkowa jest czytelna – nie można przekonwertować na liczbę ciągu znaków, któ-
ry nie reprezentuje liczby. Kolejne ćwiczenie pokaże jakie mogą być efekty pracy takiej aplikacji dla
jej użytkownika. Aby uprościć wykonanie ćwiczenia skopiuj plik wykonywalny (*.exe) z katalogu De-
bug projektu wykonanego w ćwiczeniu 95. do katalogu głównego dysku (\).
Ćwiczenie 100
Zapoznać się z „problemami” użytkownika aplikacji.
1. Uruchom wiersz poleceń systemu operacyjnego (cmd.exe) i przejdź do katalogu główne-
go wydając polecenie „cd \”.
2. Uruchom aplikację w wierszu poleceń i wprowadź jako dzielną dowolną liczbę, a jako
dzielnik tekst: Duża liczba.
Systemy operacyjne Windows w swoich kolejnych wersjach rozwojowych nieco odmiennie re-
agują na błędy czasu wykonania. Wspólna reakcja, to wyświetlenie okna Projekt_103. Okno to może
zawierać informację o tym, że wystąpił problem z tą aplikacją i zostanie ona zamknięta (XP), może
także informować o tym, że program przestał działać (Vista, 7). W Windows XP okno pozwala rozpo-
cząć debugowanie – Just-In-Time Debugging, wysłać (albo nie) raport o błędach. Okno należy za -
mknąć wybierając przycisk Nie wysyłaj. W Windows Vista (7), po zakończeniu zbierania informacji
związanych z zatrzymaniem aplikacji, zostanie wyświetlone dodatkowe okno Projekt_103, pozwalają-
ce przesłać informacje o niepowodzeniu. Należy anulować każde z okien.
3. Zauważ treści wyświetlone w wierszu poleceń:
Łatwo wyobrazić sobie „radość” użytkownika po obejrzeniu takiego obrazka.
4. Zamknij wiersz poleceń (Exit).
5. Uruchom Explorator Windows i uruchom ponownie aplikację podając te same dane i za-
mykając okno systemu operacyjnego informujące o błędzie.
Wyświetlane komunikaty mogą być dla użytkownika niezrozumiałe, a jeśli nawet są zrozumiałe,
to aplikacja z jego punktu widzenia nie jest bezpieczna. Instrukcja prowadząca do tych komunikatów,
sama w sobie, nie jest błędna. Do zatrzymania aplikacji doprowadziło działanie użytkownika, jednak
to na programiście spoczywa ciężar przewidywania takich sytuacji. Sprawdzenie jak aplikacja reaguje
na dzielnik równy zeru pozostawia się ćwiczącym do samodzielnego wykonania.
Zaprogramowanie aplikacji odpornej na nieprawidłowe dane nie jest łatwe, ale możliwe. Innym
rodzajem błędów są te wynikające z nieprawidłowej logiki, lub zastosowania nieprawidłowego bądź
błędnego algorytmu. Kolejne ćwiczenie pokazuje taki błąd projektu.
Ćwiczenie 101
Zapoznać się z działaniem aplikacji zawierającej błąd logiczny.
1. Uruchom debugowanie aplikacji (Projekt_103) i wprowadź więcej niż 10 zestawów da-
nych. Należy pamiętać, że aplikacja przechowuje w tablicy tylko 10 pierwszych zesta-
wów.
2. Odpowiedz „N” po wprowadzeniu danych. Zauważ, że aplikacja nie wyświetla historii da-
nych, ale jej praca zostaje wstrzymana, a debugger wyświetla komunikat:
IndexOutOfRangeException was unhandled – nie został obsłużony wyjątek przekroczenia za-
kresu indeksów.
Index was outside the bounds of the array – indeks nie znajdował się wewnątrz ograniczeń ta-
blicy.
3. Zamknij okno komunikatu.
4. Zauważ, że aplikacja nie zakończyła działania, edytor zaznacza wykonywany wiersz
kodu kolorem żółtym. (Nie należy przerywać działania debuggera, będzie ono kontynu-
owane w kolejnym ćwiczeniu.)
5. Zastanów się dlaczego w procedurze WyświetlHistorię, w trakcie wykonywania pętli, war-
tość zmiennej sterującej pętlą przekracza maksymalny indeks tablicy.
Odpowiedź na pytanie zawarte w ćwiczeniu wydaje się oczywista. Widocznie górne ogranicze-
nie zmiennej sterującej pętlą jest większe niż 9 (maksymalny indeks tablicy hiObliczenia). Górne
ograniczenie ma postać: LiczbaWpisow – 1. „Ktoś” pamiętał o odjęciu jedynki, aby przetworzyć natu-
ralną „liczbę wpisów” na, rozpoczynający się od zera, indeks. Skoro indeks przekroczył wartość 9, to
znaczy, że LiczbaWpisow przekroczyła wartość 10, ale to nie wina procedury WyświetlHistorię. Pro-
cedura otrzymuje liczbę wpisów jako parametr.
W tym momencie kończą się możliwości analizy kodu źródłowego. Projekt celowo jest nieskom-
plikowany, aby możliwe było naturalne przejście od pełnej wiedzy programisty na temat utworzonego
kodu do wykorzystania debuggera.
Wydaje się, że należy przejść do miejsca wywołania procedury WyświetlHistorię i będzie można
kontynuować analizę. Jednak należy zdawać sobie sprawę z tego, że projekt może zawierać więcej
niż jedno wywołanie procedury WyświetlHistorię, a wtedy nie będzie wiadomo, do którego wywołania
się cofnąć. Na szczęście debbuger nie tylko wyświetla błędy, ale także zapamiętuje wywołania, które
poprzedziły wystąpienie błędu. Kolejne ćwiczenie pokazuje wykorzystanie tej funkcjonalności.
Ćwiczenie 102
Zapoznać się z możliwością wykorzystania zapamiętanych przez debugger wywołań do
odnalezienia błędu logicznego w kodzie źródłowym.
1. Rozwiń menu Debug i wyświetl polecenia grupy Windows (postaraj się zapamiętać na-
zwy poleceń tej grupy). Zwróć szczególną uwagę na polecenie Call Stack (Stos wywo-
łań).
2. Uaktywnij okno stosu wywołań. Będzie ono zawierało treść zbliżoną do przedstawionej
w poniższym przykładzie.
Przykładowy obraz okna Call Stack.
3. Zapoznaj się z listą wywołań. Żółta strzałka wskazuje ostatnie wywołanie metody. Poniżej
wyświetlone są wywołania poprzedzające ostatnie.
4. Wyświetl miejsce wywołania metody poprzedzającej wywołanie procedury WyświetlHisto-
rię, w tym celu kliknij dwukrotnie drugi wpis w oknie Call Stack. Zauważ, że został zazna-
czony (jasnozielone tło) wiersz z wywołaniem procedury WyświetlHistorię.
5. Prześledź poprzedzające wiersz instrukcje w celu odnalezienia źródła błędu, pamiętając,
że drugi parametr (intIleZestawów) przekazany do procedury miał wartość większą niż
10, a to spowodowało przekroczenie indeksu tablicy.
Odnalezienie wiersza kodu źródłowego, w którym następuje powiększenie wartości zmiennej in-
tIleZestawów o jeden, nie jest trudne. Znajduje się on w pętli Do. Wartość tej zmiennej jest następnie
przekazywana jako parametr. Krótki namysł pozwala zrozumieć problem – intIleZestawów zlicza
wszystkie podane zestawy. Jest to zgodne z logiką działania pętli, jednak procedura WyświetlHistorię
powinna wyświetlać maksymalnie 10 zestawów. Sposobów na rozwiązanie problemu jest wiele i wy-
bór jednego z nich pozostawia się ćwiczącym jako zadanie do samodzielnego wykonania. Nasuwa
się w tym miejscu uwaga praktyczna, modyfikacja kodu powinna obejmować najmniejszy możliwy
blok. W ćwiczeniu tym blokiem jest procedura WyświetlHistorię, to ona powinna być przygotowana
pod względem bezpieczeństwa na różne zestawy danych. Wydaje się, że sprawdzenie czy drugi pa-
rametr nie ma zbyt dużej wartości powinno nastąpić przed wykonaniem pętli. Pozwoliłoby to na unik-
nięcie przekroczenia zakresu indeksów.
Przed edycją kodu należy przerwać debugowanie, lub włączyć zezwolenie na edycję kodu pod-
czas przerwania wykonywania aplikacji (odpowiednia opcja dostępna jest po wybraniu menu Tools,
następnie polecenia Options i zakładki Edit and Continue folderu Debugging – Enable Edit and Conti-
nue).
Programy zawierają ciągi obliczeń, procedury i funkcje. Korzystając ze sprawdzonych wcześniej
procedur i funkcji możemy założyć, że będą one działać bezbłędnie również w projektowanej aplika -
cji. Może się jednak zdarzyć, że np. ciąg obliczeń doprowadzi do nieprawidłowego wyniku. W takim
przypadku należałoby przeanalizować algorytm i porównać go z wykonywanym kodem. Jeśli wyniki
otrzymane tradycyjną metodą – papier i ołówek, różnią się od wyników otrzymywanych w aplikacji, to
należy domniemywać, że implementacja algorytmu zawiera błąd. Kolejne ćwiczenie, w oparciu
o działania na liczbach zespolonych, zobrazuje opisany przypadek.
Przypomnienie. Jednostka urojona, to liczba i o następującej właściwości: i
2
=-1. Wyrażenie
o postaci a+ib nazywa się liczbą zespoloną, przy tym a nazywa się częścią rzeczywistą, b częścią
urojoną liczby zespolonej. Dla liczb zespolonych z
1
=a
1
+ib
1
oraz z
2
=a
2
+ib
2
definiuje się operacje aryt-
metyczne:
Dodawanie
z
1
z
2
=
a
1
ib
1
a
2
ib
2
=
a
1
a
2
ib
1
b
2
Odejmowanie
z
1
−
z
2
=
a
1
ib
1
−
a
2
ib
2
=
a
1
−
a
2
i b
1
−
b
2
Mnożenie
z
1
z
2
=
a
1
ib
1
a
2
ib
2
=
a
1
a
2
−
b
1
b
2
i a
1
b
2
a
2
b
1
Dzielenie
z
1
z
2
=
a
1
ib
1
a
2
ib
2
=
a
1
ib
1
a
2
ib
2
⋅
a
2
−
ib
2
a
2
−
ib
2
=
a
1
a
2
b
1
b
2
i a
2
b
1
−
a
1
b
2
a
2
2
b
2
2
=
a
1
a
2
b
1
b
2
a
2
2
b
2
2
i
a
2
b
1
−
a
1
b
2
a
2
2
b
2
2
Błąd będzie zawarty w funkcji obliczającej iloraz dwóch liczb zespolonych. Zatem wyniki będą
oczywiście fałszywe.
Ćwiczenie 103
Zapoznać się z kodem źródłowym Projekt_103. Porównać wyniki działania aplikacji tego
projektu z wynikami działania aplikacji Projekt_103OK.exe.
1. Otwórz Projekt_103 i zapoznaj się z jego kodem źródłowym, w tym z kodem modułu Ze-
spolone.vb.
2. Uruchom aplikację projektu i wprowadź dane, nie kończ działania aplikacji.
3. Uruchom aplikację Projekt_103OK.exe i wprowadź dane identyczne jak w poprzednim
punkcie. Zwróć uwagę na różnicę wartości obliczonych przez oba programy ilorazów.
4. Zakończ działanie obu aplikacji.
Procedura Main Projekt_103 zawiera kilka instrukcji wynikających z potrzeb użytkownika.
Na program składają się: pobranie wartości dwóch liczb zespolonych i wyświetlenie wyników czte-
rech podstawowych działań arytmetycznych. Moduł Zespolone zawiera funkcje przydatne do wykony-
wania obliczeń. Kod źródłowy niektórych z tych funkcji został skomplikowany, aby pokazać możliwo-
ści debuggera.
Przyjrzyjmy się ponownie deklaracji różnicy dwóch liczb zespolonych:
z
1
−
z
2
=
a
1
ib
1
−
a
2
ib
2
=
a
1
−
a
2
i b
1
−
b
2
Zauważmy, że możemy zastąpić odejmowanie sumowaniem:
z
1
−
z
2
=
a
1
ib
1
−
a
2
−
ib
2
=
a
1
−
a
2
ib
1
−
b
2
Liczba w nawiasie występującym po znaku sumy, to liczba przeciwna do pierwotnego odjemni -
ka. (Właściwością liczb przeciwnych jest to, że ich suma jest zerem.) Można zatem odejmowanie za-
stąpić dodawaniem liczby przeciwnej do odjemnika. Taki algorytm został zaimplementowany w funkcji
Różnica. Oznacza to, że funkcja Różnica, w celu obliczenia wyniku, wywołuje funkcję Suma prze-
kazując jako drugi parametr liczbę przeciwną do odjemnika.
W związku z powyższym śledzenie przepływu sterowania w aplikacji staje się utrudnione. De-
bugger pozwala w tym zakresie, między innymi, na:
wstrzymanie wykonywania aplikacji – decyzję o wstrzymaniu podejmuje programista w trakcie
wykonywania aplikacji, a edytor zaznacza w kodzie źródłowym instrukcję, która będzie wyko-
nywana jako następna, albo wykonywaną instrukcję, jeśli przerwanie nastąpiło przed zakoń-
czeniem jej wykonywania,
wstrzymanie wykonywania aplikacji przed wykonaniem określonej instrukcji – decyzję
o wstrzymaniu podejmuje programista na etapie projektowania; po zatrzymaniu, edytor ozna-
cza instrukcję, która będzie wykonywana jako następna,
wstrzymanie wykonywania aplikacji przed wykonaniem określonej instrukcji, ale tylko wtedy,
gdy spełnione są wyspecyfikowane przez programistę warunki – decyzja o wstrzymaniu oraz
warunki wstrzymania ustalane są na etapie projektowania,
wykonanie pojedynczej instrukcji,
wykonanie metody bez śledzenia wykonywania kolejnych instrukcji bloku metody.
We wszystkich wymienionych przypadkach możliwy jest przegląd aktualnych wartości zmien-
nych. Wstrzymanie wykonywania aplikacji „na żądanie” wykonuje się w trakcie działania aplikacji. Ilu-
struje to kolejne ćwiczenie, które dodatkowo zapoznaje ze sposobami krokowego (instrukcja po in-
strukcji) wykonywania aplikacji.
Ćwiczenie 104
Zapoznać się z możliwością wstrzymania pracy aplikacji i śledzenia wykonywania
kolejnych instrukcji kodu źródłowego.
1. Uruchom debugowanie aplikacji Projekt_103. Początkowe działanie programu polega
na pobraniu od użytkownika wartości części rzeczywistej pierwszej liczby zespolonej. Nie
należy wprowadzać tej wartości.
2. Wstrzymaj działanie aplikacji przed wprowadzeniem wartości części rzeczywistej pierw-
szej liczby zespolonej, w tym celu:
◦
uaktywnij Visual Studio 2010 (przełącz aktywność z konsoli aplikacji Projekt_103
na okno środowiska),
◦
rozwiń menu Debug i zauważ, że aktywne jest polecenie Break All – Ctrl+Break
(Przerwij wszystko),
◦
wybierz polecenie Break All i zauważ, że w kodzie źródłowym pojawiła się jasnozielo-
na strzałka wskazująca aktualnie wykonywaną instrukcję przypisania – nie została
ona zakończona, gdyż użytkownik nie wprowadził wartości.
3. Uaktywnij konsolę aplikacji Projekt_103 i wprowadź wartość części rzeczywistej pierw-
szej liczby zespolonej. Zauważ, że aplikacja nie wykonuje dalszych instrukcji.
4. Uaktywnij Visual Studio 2010 – edytor w dalszym ciągu wskazuje, że instrukcja przypisa-
nia jest w trakcie wykonywania; tekst podany przez użytkownika został pobrany przez in-
strukcję ReadLine, lecz nie został jeszcze skonwertowany na typ Double. Konwersja zo-
stanie wykonana jako kolejny krok.
5. Spowoduj wykonanie kolejnego kroku w działaniu aplikacji – konwersji tekstu na typ Do-
uble, w tym celu:
◦
rozwiń menu Debug i zapoznaj się z trzema instrukcjami rozpoczynającymi się od sło-
wa Step:
Step Into – F8 (Krok do) – powoduje wykonanie kolejnej instrukcji kodu źródło-
wego, a jeśli instrukcja wywołuje jakąkolwiek metodę, której deklaracja jest do-
stępna w projekcie, to kolejną instrukcją, zaznaczoną jako instrukcja do wykona-
nia, będzie pierwsza instrukcja metody; oznacza to, że polecenie Step Into po-
woduje kolejne wykonywanie wszystkich instrukcji kodu,
Step Over – Shift+F8 (Krok nad) – powoduje wykonanie kolejnej instrukcji kodu
źródłowego, a jeśli instrukcja wywołuje jakąkolwiek metodę, to instrukcje bloku
metody będą wykonane bez śledzenia; oznacza to, że polecenie Step Over po-
mija śledzenie metod wywoływanych przez wykonywaną instrukcję kodu źródło-
wego, działanie takie jest przydatne, gdy programista jest przekonany, że meto-
dy wywoływane w instrukcji nie powodują błędu, który chce wyśledzić,
Step Out – Ctrl+Shift+F8 (Krok na zewnątrz) – powoduje wykonanie wszystkich
instrukcji do końca bloku, w którym znajduje się instrukcja wskazywana przez
edytor; oznacza to, że polecenie Step Out powoduje zakończenie śledzenia wy-
konywania instrukcji w danym bloku, działanie takie jest przydatne, gdy progra-
mista jest przekonany, że pozostałe instrukcje bloku nie powodują błędu, który
chce wyśledzić;
◦
zauważ, że przyciski poznanych poleceń znajdują się na pasku narzędzi Debug,
◦
uruchom polecenie Step Into,
◦
zauważ, że edytor zaznaczył (żółte tło) instrukcję, która ma być wykonana jako na-
stępna i jest to instrukcja przypisania (warto uzmysłowić sobie, że instrukcja ta była
poprzedzona pobraniem wartości z konsoli i skonwertowaniem jej na typ Double).
6. Spowoduj wykonanie instrukcji przypisania – Step Into (lub Step Over).
7. Spowoduj wykonanie instrukcji programu, do momentu, aż kolejną instrukcją do wykona-
nia będzie Console.WriteLine w wierszu 17.
8. Uruchom polecenie Step Into. Zauważ, że edytor wyświetla nagłówek funkcji Zespolona-
Tekstem z modułu Zespolone.
9. Załóż, że funkcja jest napisana poprawnie i można pominąć jej krokowe wykonanie. Uru-
chom polecenie Step Out.
10.Przerwij stan przerwania, w którym znajduje się aplikacja, w tym celu:
◦
rozwiń menu Debug i zauważ, że aktywne jest polecenie Continue – F5 (Kontynuuj),
służy ono tak, do rozpoczęcia pracy aplikacji, jak i do wyprowadzenia jej ze stanu
przerwania,
◦
uruchom polecenie Continue (odpowiedni przycisk znajduje się również na pasku na-
rzędzi Debug).
11. Dokończ pracę aplikacji.
Polecenia Step pozwalają programiście zapanować nad procesem krokowego wykonywania
aplikacji. Ich użycie możliwe jest jedynie w trybie przerwania pracy aplikacji. Przerwanie pracy aplika-
cji w przypadku, gdy oczekuje ona na działania ze strony użytkownika nie nastręcza trudności. Jed-
nak, po wprowadzeniu danych (obu liczb zespolonych), próba zatrzymania, np. przed wykonaniem
mnożenia, musi zakończyć się niepowodzeniem. W takim przypadku, decyzję o wstrzymaniu pracy
programista musi podjąć już na etapie projektowania. Narzędziem, które pozwala na takie działanie
jest punkt przerwania (ang. breakpoint). Kolejne ćwiczenie pokazuje metodykę umieszczania punk-
tów przerwania w kodzie źródłowym.
Ćwiczenie 105
Zapoznać się z metodyką umieszczania punktu przerwania w kodzie źródłowym.
1. Ustaw kursor tekstowy w wierszu procedury Main poświęconym obliczeniu i wyświetleniu
iloczynu liczb zespolonych (linia 34 modułu – aby włączyć numerację wierszy w kodzie
źródłowym wybierz menu Tools, polecenie Options, folder Text Editor\Basic
, pole wyboru
Line numbers).
2. Rozwiń menu Debug i zapoznaj się z poleceniem Toggle Breakpoint – F9 (Przełącz punkt
przerwania – słowo „przełącz” oznacza w tym kontekście: włącz jeśli jest wyłączony, wy-
łącz jeśli jest włączony).
3. Włącz punkt przerwania w 9. wierszu kodu źródłowego, w tym celu uruchom polecenie
Toggle Breakpoint.
4. Zauważ, zmiany wprowadzone przez edytor:
◦
tło wiersza z punktem przerwania zostało zmienione na brązowe,
◦
na lewo od numeru wiersza pojawił się symbol brązowej, oświetlonej półkuli – zasad-
niczy wskaźnik punktu przerwania.
5. Sprawdź działanie punktu przerwania uruchamiając debugowanie.
6. Zakończ działanie aplikacji poleceniem Stop Debugging z menu Debug.
Aplikacja zatrzymuje się po wyświetleniu sumy i różnicy liczb zespolonych. Edytor wskazuje in-
strukcję z punktem przerwania (żółta strzałka na brązowej kuli punktu przerwania, żółte tło instrukcji,
która będzie wykonana jako następna). Dalsze debugowanie polega na wykorzystaniu poleceń z gru -
py Step. Prosty punkt przerwania można ustawić także używając myszy. Polega to na kliknięciu
w obszarze po lewej stronie numeracji, gdy kursor myszy wskazuje w lewą stronę (gdy kursor wska-
zuje w prawą stronę następuje zaznaczenie wiersza
), na wysokości wiersza, w którym ma się poja-
wić punkt przerwania.
7 Jeśli pole wyboru Show all settings nie jest zaznaczone, to pole wyboru Line numbers znajduje się w podfolderze Edi -
tor folderu Basic.
8 W poprzednich wersjach środowiska zadanie było nieco łatwiejsze, gdyż obszar punktów przerwania oznaczony był
kolorem szarym (pionowa szara belka).
Punkty przerwania można usuwać pojedynczo, lub wszystkie, a także wyłączać ich działanie
bez usuwania. Do usunięcia wszystkich punktów przerwania służy polecenie Delete All Breakpoints
z menu Debug. Pojedynczy punkt przerwania można usunąć wybierając grupę poleceń Breakpoint,
a następnie polecenie Delete Breakpoint z menu kontekstowego wiersza z punktem przerwania, albo
klikając półkulę w belce po lewej stronie edytora. Do przeglądania punktów przerwania służy okno
Breakpoints (menu Debug, grupa poleceń Windows, polecenie Breakpoints).
Punkt przerwania może działać warunkowo, to znaczy – przerwanie nastąpi tylko wtedy, gdy ma
nastąpić wykonanie instrukcji z punktem przerwania i jest spełniony pewien ustalony warunek. Kolej-
ne ćwiczenie poświęcone jest ustaleniu warunku dla istniejącego punktu przerwania.
Ćwiczenie 106
Ustalić, że ustalony w pliku Start_105.vb punkt przerwania ma działać tylko wtedy, gdy
spełniony jest pewien warunek.
1. Uaktywnij okno Breakpoints i zapoznaj się z jego paskiem narzędzi.
2. Zaznacz w oknie jedyny punkt przerwania.
3. Uruchom okno Breakpoint Condition, w tym celu:
◦
rozwiń menu kontekstowe dla zaznaczonego punktu przerwania i zapoznaj się z do-
stępnymi poleceniami,
◦
wybierz polecenie Condition – pojawia się okno Breakpoint Condition,
◦
zapoznaj się z zawartością okna.
Przykład.
Komunikat okna głosi: W chwili osiągnięcia punktu przerwania, przeliczane jest wyrażenie i jeśli
jego wartość wynosi true, albo zmieniła się, to punkt przerwania zadziała.
4. Ustal, że punkt przerwania ma działać tylko wtedy, gdy część rzeczywista zmiennej Z1 i
część rzeczywista zmiennej Z1 są równe, w tym celu:
◦
pozostaw zaznaczenie w polu wyboru Condition (pozwala włączyć lub wyłączyć dzia-
łanie warunku wprowadzonego do pola tekstowego),
◦
ustal, wybierając odpowiednią opcję, że warunek powinien zadziałać nie wtedy, gdy
wartość wyrażenia się zmieni (Has changed), ale wtedy gdy ma wartość true (Is true),
◦
wpisz w pole tekstowe warunek: Z1.Re=Z2.Re.
◦
zatwierdź wprowadzone zmiany przyciskiem Ok,
◦
zauważ, że punkt przerwania w oknie Breakpoints (także w edytorze kodu źródłowe-
go) otrzymał dodatkowo biały znak + oznaczający, że punkt przerwania posiada do-
datkowe ustawienia.
5. Sprawdź działanie punktu przerwania przy różnych zestawach danych.
Debugowanie umożliwia ustalenie wielu dróg poszukiwania błędu w kodzie źródłowym. Wcze-
śniej zostało zasygnalizowane, że w trybie przerwania istnieje możliwość przeglądania wartości
zmiennych użytych w programie. Najłatwiejszym sposobem jest w tym zakresie wykorzystanie okna
Autos. Okno to, uaktywniane w trybie przerwania poleceniem Autos (grupa poleceń Windows w menu
Debug) wyświetla wartości zmiennych używanych w zaznaczonej instrukcji oraz w instrukcji poprzed-
niej. Okno pokazuje nazwę, wartość oraz typ zmiennej. Zmienne złożone można rozwijać używając
ikony ze znakiem +. Kolejne ćwiczenie pokazuje wykorzystanie okna Autos.
Ćwiczenie 107
Śledzić wartości zmiennych w trakcie przerw w wykonywaniu aplikacji.
1. Ustaw punkt przerwania w nagłówku procedury Main, w tym celu:
◦
wybierz przycisk New w pasku narzędzi okna Brakpoints,
◦
wybierz polecenie Break at Function pojawi się jedna z kilku wersji okna New Break-
point,
◦
wpisz w pole tekstowe nazwę procedury – Main,
◦
zatwierdź zmiany przyciskiem Ok,
◦
zauważ, że punkt przerwania wskazywany jest jedynie przez brązową półkulę.
2. Uruchom debugowanie. Wykonywanie aplikacji zostaje przerwane przed wykonaniem
którejkolwiek instrukcji procedury Main, której nagłówek jest zaznaczony żółtym tłem.
3. Uaktywnij okno Autos wybierając menu Debug, grupę poleceń Windows i polecenie Au-
tos – Ctrl+Alt+V, A (po wybraniu sekwencji Ctrl+Alt+V, należy uderzyć klawisz z literą A).
4. Wykonaj polecenie Step Over przechodząc kolejno przez instrukcje procedury Main,
aż do osiągnięcia wiersza nr 13.
5. Rozwiń w oknie Autos pola zmiennej Z1.
6. Wykonaj polecenie Step Over przechodząc kolejno przez wszystkie instrukcje procedury
Main, jeśli to potrzebne, w odpowiednich chwilach wprowadź dane. Obserwuj zmiany za-
chodzące w oknie Autos.
Śledzenie zmian wartości zmiennych w oknie Autos ułatwia fakt, że każda wartość, która uległa
zmianie jako ostatnia, zaznaczana jest kolorem czerwonym. Innym sposobem na przeglądanie warto-
ści jest wykorzystanie okna Locals. Pokazuje ono wartości zmiennych, które są lokalne w bloku in-
strukcji, który jest aktualnie wykonywany. Okno Locals uruchamia się w podobny sposób jak okno Au-
tos. Prześledzenie zmian wartości lokalnych w trakcie przerw w wykonywaniu aplikacji pozostawia
się ćwiczącym do samodzielnego wykonania. Ostatnim z omawianych sposobów przeglądania warto-
ści zmiennych jest wykorzystanie okna Watch. Oprócz walorów proponowanych przez okna Autos i
Locals okna Watch pozwalają wyświetlać również wartości wyrażeń, a także zmieniać wartości
zmiennych. Kolejne ćwiczenie polegać będzie na wykorzystaniu pierwszego okna Watch.
Ćwiczenie 108
Wykorzystać okno Watch do przeglądania wartości zmiennych i wyrażeń oraz
modyfikacji wartości zmiennych.
1. Uruchom debugowanie i włącz okno Watch 1 (Debug\Windows).
2. Dodaj do okna możliwość śledzenia wartości pola Re zmiennej Pierwsza, w tym celu klik-
nij puste pole Name w pierwszym wierszu okna i wprowadź nazwę pola do śledzenia –
Z1.Re.
3. Przeprowadź aplikację przez etap wprowadzania danych.
4. Dodaj do okna możliwość śledzenia wyniku funkcji ZespolonaTekstem dla argumentu Z2,
w tym celu wprowadź odpowiednie wywołanie – ZespolonaTekstem(Z2) – w polu Name
drugiego wiersza okna Watch 1.
5. Dodaj do okna możliwość śledzenia wartości iloczynu Z1.Re * Z2.Re.
6. Zmień wartość pola Re zmiennej Z1, w tym celu:
◦
zaznacz pierwszy wiersz w oknie Watch 1,
◦
kliknij dwukrotnie, szybko pole Value – przejdzie ono w tryb edycji,
◦
wprowadź nową wartość i zatwierdź ją,
◦
zauważ zmianę wartości iloczynu w trzecim wierszu okna Watch 1.
Okna Watch pozwalają grupować przeglądane wartości w taki sposób, aby przynieść programi-
ście optymalną liczbę informacji na danym etapie pracy aplikacji. Ułatwia to poszukiwanie błędów
w kodzie źródłowym.