Ćwiczenie — debugowanie za pomocą programu Visual Studio

Ukończone

Nadszedł czas, aby przećwiczyć nowo zdobytą wiedzę na temat debugowania. To twój pierwszy dzień w pracy i chcesz wykorzystać swoje umiejętności debugowania na platformie .NET, aby naprawić usterkę w flagowym produkcie firmy, którym jest kalkulator Fibonacciego.

Tworzenie przykładowego projektu platformy .NET na potrzeby debugowania

Aby skonfigurować debugowanie programu Visual Studio dla platformy .NET, najpierw potrzebujemy projektu platformy .NET. Program Visual Studio udostępnia mnóstwo szablonów startowych, które ułatwiają tworzenie nowego projektu.

  1. W programie Visual Studio wybierz pozycje Plik>Nowy>Projekt.

  2. W oknie dialogowym Tworzenie nowego projektu wybierz pozycję Aplikacja konsolowa, a następnie wybierz pozycję Dalej.

  3. Nadaj projektowi nazwę DotNetDebugging i wybierz lokalizację, w której chcesz zapisać. Pozostaw wartości domyślne pozostałych, a następnie wybierz pozycję Dalej.

  4. Wybierz pozycję Utwórz na ekranie końcowym.

Program Visual Studio tworzy dla nas projekt Konsoli przy użyciu wybranego szablonu. Po załadowaniu projektu otwórz Program.cs , wybierając go.

Dodawanie logiki programu Fibonacciego

Nasz bieżący projekt wypisuje w konsoli komunikat „Hello World”, co nie dostarcza nam zbyt wielu danych do debugowania. Zamiast tego użyjemy krótkiego programu .NET, aby obliczyć Nnumer sekwencji Fibonacciego.

Ciąg Fibonacciego to zbiór liczb rozpoczynający się od cyfr 0 i 1, przy czym każda kolejna liczba jest sumą dwóch poprzednich. Sekwencja będzie wyglądać następująco:

0, 1, 1, 2, 3, 5, 8, 13, 21...

Poniższy przykładowy kod zawiera usterkę, więc użyjemy narzędzi debugowania programu Visual Studio, aby zdiagnozować i rozwiązać ten problem.

  1. Zastąp zawartość pliku Program.cs następującym kodem:
int result = Fibonacci(5);
Console.WriteLine(result);

static int Fibonacci(int n)
{
    Console.WriteLine("The output is: ");
    int n1 = 0;
    int n2 = 1;
    int sum;

    for (int i = 2; i < n; i++)
    {
        sum = n1 + n2;
        n1 = n2;
        n2 = sum;
    }

    return n == 0 ? n1 : n2;
}

Uwaga

Ten kod zawiera błąd, który naprawiamy w dalszej części tego modułu. Nie zaleca się używania go w żadnej aplikacji Fibonacciego o znaczeniu krytycznym, dopóki ta usterka nie zostanie naprawiona.

  1. Zapisz plik za pomocą Ctrl+S dla systemów Windows i Linux. Na komputerach Mac wybierz klawisze Cmd+S.

  2. Przyjrzyjmy się, jak działa zaktualizowany kod przed jego zdebugowaniem. Uruchom program, naciskając zielony przycisk startowy na pasku poleceń programu Visual Studio.

  3. Na końcu danych wyjściowych konsoli debugowania widać, że program wypisuje 3 na konsolę, a następnie kończy działanie z kodem 0. Zazwyczaj kod zakończenia programu 0 wskazuje, że program został uruchomiony i zakończony bez awarii. Istnieje jednak różnica między awarią i zwróceniem poprawnej wartości.

Okno terminalu ze zmodyfikowanymi danymi wyjściowymi programu.

W tym przypadku poprosiliśmy program, aby obliczał piątą wartość sekwencji Fibonacciego:

0, 1, 1, 2, 3, 5, 8, 13, 21...

Piąta wartość na tej liście to 5, ale nasz program zwrócił wartość 3. Użyjmy debugera, aby zdiagnozować i usunąć ten błąd.

Użyj punktów przerwania i wykonuj krok po kroku

  1. Dodaj punkt przerwania, klikając w lewym marginesie przy linii 1 na int result = Fibonacci(5);.

  2. Ponownie uruchom debugowanie. Program zaczyna się wykonywać. Przerywa (wstrzymuje wykonywanie) w wierszu 1 ze względu na ustawiony punkt przerwania. Użyj kontrolek debugera, aby przejść do funkcji Fibonacci().

    Zrzut ekranu przycisku 'Przejdź do środka'.

Sprawdzanie stanu zmiennych

Teraz poświęć trochę czasu, aby sprawdzić wartości różnych zmiennych, korzystając z okna Zmienne lokalne.

Zrzut ekranu przedstawiający panel Ustawienia lokalne.

  • Jaka jest pokazana wartość parametru n?
  • Jakie są wartości zmiennych lokalnych n1, n2 i sum na początku wykonywania funkcji?
  1. Następnie przechodzimy do pętli przy użyciu kontrolki forDebuger krok po kroku.

    Zrzut ekranu przedstawiający przycisk krok przez.

  2. Kontynuuj przechodzenie, aż osiągniesz pierwszy wiersz w pętli for. Linia, która brzmi:

    sum = n1 + n2;
    

Uwaga

Możesz zauważyć, że przejście przez linię for(...) {} wymaga wykonania kilku kroków polegających na wprowadzaniu różnych poleceń. Sytuacja ta występuje, ponieważ w tym wierszu znajduje się wiele instrukcji. Gdy wykonasz krok, przechodzisz do następnej instrukcji w kodzie. Zazwyczaj jest jedno wyrażenie na wiersz. Jeśli to nie jest prawda, musisz wykonać wiele kroków, aby przejść do następnego wiersza.

Myśl o kodzie

Ważną częścią debugowania jest zatrzymanie się i zastanowienie się nad tym, co Twoim zdaniem próbują zrobić fragmenty kodu (funkcje i bloki, takie jak pętle). Jeśli nie masz pewności, nie ma problemu — jest to część procesu debugowania. Jednak aktywne zaangażowanie w proces debugowania ułatwia szybsze lokalizowanie usterek.

Przed zapoznaniem się z dalszymi szczegółami przypomnijmy, że ciąg Fibonacciego to seria liczb rozpoczynająca się od cyfr 0 i 1, w którym każda kolejna liczba jest sumą dwóch poprzednich.

Oznacza to, że:

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1 (0 + 1)
Fibonacci(3) = 2 (1 + 1)
Fibonacci(4) = 3 (1 + 2)
Fibonacci(5) = 5 (2 + 3)

Jeśli rozumiemy tę definicję i przyjrzymy się pętli for, możemy wydedukować, że:

  1. Pętla liczy od 2 do n (liczba ciągu Fibonacciego, której szukamy).
  2. Jeśli n wartość jest mniejsza niż 2, pętla nigdy nie jest uruchamiana. Instrukcja return na końcu funkcji zwraca wartość 0, jeśli n ma wartość 0, i 1, jeśli n ma wartość 1 lub 2. Te wartości to wartości zero, pierwsze i drugie w serii Fibonacciego według definicji.
  3. Bardziej interesujący przypadek występuje, gdy wartość n jest większa niż 2. W takich przypadkach bieżąca wartość jest definiowana jako suma dwóch poprzednich wartości. Dla tej pętli n1 i n2 są dwiema poprzednimi wartościami, a sum jest wartością dla bieżącej iteracji. Ze względu na tę logikę za każdym razem, gdy obliczamy sumę poprzednich dwóch wartości i ustawiamy ją na sum, aktualizujemy nasze n1 wartości i n2 .

W porządku, dalej nie musimy się zbytnio w to zagłębiać. Możemy w pewnym stopniu polegać na naszym debugerze. Warto jednak zastanowić się nad kodem, aby sprawdzić, czy robi to, czego oczekujemy, i wiedzieć, co zrobić, jeśli kod nie zachowuje się zgodnie z oczekiwaniami.

Zlokalizuj usterkę za pomocą punktów przerwania

Przechodzenie przez kod może być przydatne, ale może być również żmudne. Szczególnie w przypadku pracy z pętlami lub innym kodem, który jest wywoływany wielokrotnie. Zamiast wiele razy przechodzić przez pętlę, można ustawić nowy punkt przerwania w pierwszym wierszu pętli.

Ważne jest, aby podejść strategicznie do umieszczania naszych punktów podziału. Jesteśmy szczególnie zainteresowani wartością sum, ponieważ reprezentuje bieżącą maksymalną wartość ciągu Fibonacciego. Dlatego umieśćmy nasz punkt przerwania w wierszu posum ustawieniu.

  1. Dodaj drugi punkt przerwania w wierszu 14.

    Zrzut ekranu przedstawiający ustawianie drugiego punktu przerwania.

    Uwaga

    Jeśli zauważysz, że nadal uruchamiasz swój kod, a następnie przechodzisz przez jeden lub dwa wiersze, możesz łatwo zaktualizować punkty przerwania do efektywniejszych wierszy.

  2. Teraz, gdy mamy dobry punkt przerwania ustawiony w pętli, wybierz pozycję Kontynuuj w kontrolkach debugera, aby przejść do momentu osiągnięcia punktu przerwania. Patrząc na nasze zmienne lokalne, zobaczymy następujące wiersze:

    n [int]: 5
    n1 [int]: 0
    n2 [int]: 1
    sum [int]: 1
    i [int]: 2
    

    Wszystkie te wiersze wydają się być poprawne. Podczas pierwszego przejścia przez pętlę element sum dla poprzednich dwóch wartości wynosi 1. Zamiast krokowo przechodzić przez kolejne wiersze, możemy skorzystać z naszych punktów przerwania, aby przenieść się do kolejnego przebiegu pętli.

  3. Wybierz pozycję Kontynuuj, aby kontynuować przepływ programu do momentu, gdy zostanie trafiony następny punkt przerwania, czyli podczas następnego przejścia przez pętlę.

    Uwaga

    Nie martw się zbytnio o pominięcie usterki, gdy używasz Kontynuuj. Należy się spodziewać, że możesz debugować za pomocą kodu kilka razy, aby znaleźć problem. Często szybciej jest przejść przez coś kilka razy niż być zbyt ostrożnym za pierwszym razem.

    Tym razem zobaczysz następujące wartości:

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 1
    sum [int]: 2
    i [int]: 3
    

    Czy te wartości nadal mają sens? Wygląda na to, że tak. W przypadku trzeciej liczby ciągu Fibonacciego oczekujemy, że nasz element sum będzie mieć wartość 2, i faktycznie tak jest.

  4. Wybierz pozycję Kontynuuj, aby zapętlić ją ponownie.

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 2
    sum [int]: 3
    i [int]: 4
    

    Wynik jest poprawny. Czwarta wartość w serii powinna wynosić 3.

  5. W tym momencie można zacząć się zastanawiać, czy może kod był przez cały czas prawidłowy, a usterka powstała tylko w Twojej wyobraźni! Przejdźmy po raz ostatni przez pętlę. Wybierz pozycję Kontynuuj jeszcze jeden raz.

    Program zakończył działanie, a dane wyjściowe to 3! Nasz wynik jest niepoprawny.

    Wiemy teraz, że kod przechodzi przez pętlę prawidłowo do momentu, gdy wartość i jest równa 4, ale następnie kończy działanie przed obliczeniem końcowej wartości. Zawęziliśmy miejsce, w którym znajduje się usterka.

  6. Ustawmy jeszcze jeden punkt przerwania w wierszu 18, który brzmi:

    return n == 0 ? n1 : n2;
    

    Ten punkt przerwania pozwala nam sprawdzić stan programu przed zamknięciem funkcji. Dowiedzieliśmy się już wszystkiego, czego można się spodziewać po naszych poprzednich punktach przerwania na liniach 1 i 13, więc możemy je usunąć.

  7. Usuń poprzednie punkty przerwania w wierszach 1 i 13. Zaznacz punkty przerwania na marginesie obok numerów wierszy lub wyczyść pola wyboru punktu przerwania dla wierszy 1 i 13 w okienku punktów przerwania w lewym dolnym rogu.

    Zrzut ekranu przedstawiający punkty przerwania wyświetlane w okienku punktów przerwania.

    Teraz, gdy lepiej zrozumieliśmy, co się dzieje, możemy ustawić punkt przerwania zaprojektowany, aby przyłapać nasz program na błędnym działaniu. Teraz powinniśmy być w stanie złapać tę usterkę!

  8. Uruchom debugera po raz ostatni.

    n [int]: 5
    n1 [int]: 2
    n2 [int]: 3
    sum [int]: 3
    

    Specjalnie poprosiliśmy o Fibonacciego(5), a otrzymaliśmy Fibonacciego(4), co jest niepoprawne. Ta funkcja zwraca wartość n2, a każda iteracja pętli oblicza wartość sum i ustawia element n2 równy sum.

    Na podstawie tych informacji i poprzedniego przebiegu debugowania możemy zobaczyć, że pętla zakończyła się, gdy element i miał wartość 4, a nie 5.

    Przyjrzyjmy się bliżej naszej for pętli.

    for (int i = 2; i < n; i++)
    

    Ta logika powoduje, że program zakończy działanie, gdy tylko początek pętli for porówna i do n. Oznacza to, że kod pętli nie jest uruchamiany w przypadku, gdy i jest równa n. Wygląda na to, że w zamian chcieliśmy uruchomić kod do i <= n:

    for (int i = 2; i <= n; i++)
    

    W związku z tym zaktualizowany program powinien wyglądać tak jak w tym przykładzie:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        Console.WriteLine("The output is: ");
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i <= n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    
  9. Zatrzymaj sesję debugowania, jeśli jeszcze tego nie zrobiono.

  10. Wprowadź poprzednią zmianę w wierszu 11 i pozostaw punkt przerwania w wierszu 18.

  11. Uruchom ponownie debuger. Tym razem po osiągnięciu punktu przerwania w wierszu 18 zobaczymy następujące wartości:

    n [int]: 5
    n1 [int]: 3
    n2 [int]: 5
    sum [int]: 5
    

    Hej! Wygląda na to, że to mamy! Świetna robota, uratowałeś dzień dla Fibonacciego, Inc.!

  12. Wybierz pozycję Kontynuuj, aby upewnić się, że program zwraca poprawną wartość.

    5
    The program '[105260] DotNetDebugging.dll' has exited with code 0 (0x0).
    

    To zwraca prawidłowy wynik.

Udało Ci się! Debugowałeś kod, którego nie napisałeś, używając debugera platformy .NET w programie Visual Studio.

W następnej lekcji dowiesz się, jak ułatwić debugowanie kodu przy użyciu funkcji rejestrowania i śledzenia wbudowanych w platformę .NET.