User Tools

Site Tools


dydaktyka:cprog:2016:loops

This is an old revision of the document!


Pętla "while", debuggowanie

Cel laboratorium

  • Omówienie priorytetów operatorów.
  • Zapoznanie z pętlą while i do-while.
  • Umiejętność posługiwania się debuggerem.

Priorytet operatorów

Priorytet operatorów oznacza to samo, co kolejność działań w matematyce – operator o wyższym priorytecie zostanie wykonany najpierw, a gdy obok siebie stoją, to operacje są wykonywane od lewej do prawej (chyba, że sam operator działa inaczej, o czym za chwilę).

Przykładowo – w matematyce – wyrażenie $(2+2 \cdot 2) \cdot 2$ zostanie obliczone w następujących krokach:

  1. Obliczenie wartości w nawiasie:
    1. Obliczenie $2 \cdot 2 = 4$
    2. Obliczenie $2 + 4 = 6$
  2. Obliczenie $6 \cdot 2 = 12$

Dlaczego tak? Ponieważ – mówiąc językiem programisty – nawiasy mają najwyższy priorytet, a mnożenie ma wyższy priorytet od dodawania.

Zapoznaj się z tabelą priorytetów operatorów w języku C (uwaga: wielu z zawartych w niej operatorów jeszcze nie znasz, lecz część z nich wprowadzimy sukcesywnie na kolejnych zajęciach).
Zwróć uwagę na kolumnę Associativity, czyli “kierunek wiązania”. Oznacza to, która strona operatora zostanie obliczona w pierwszej kolejności (np. Left-to-right oznacza, że najpierw obliczona zostanie lewa strona operatora) i niejako “w którą stronę działa operator” – przykładowo operator przypisania = przypisuje wartość stojącą po jego prawej stronie zmiennej stojącej po lewej stronie, zatem jego kierunek wiązania to Right-to-Left.

Tak więc, można stwierdzić, że każde wyrażenie w języku C ma pewną wartość, obliczoną zgodnie z priorytetami i kierunkami wiązania operatorów.

:!: Nie musisz pamiętać całej tej terminologii, lecz musisz kojarzyć o co w tym wszystkim chodzi.


Zadanie 1
Napisz program sprawdzający, czy dla zadanej przez użytkownika liczby $x$ zachodzi $4 < x < 6$.
Przetestuj swój program dla $x = 5$ oraz dla $x = 7$.

Pętla "while"

Pętla while wykonuje instrukcję dopóty, dopóki spełniony jest warunek testowy (tzn. wyrażenie podane jako warunek ma wartość niezerową).

Ogólna postać:

while (wyrażenie_testowe)
    instrukcja

Pętla while to pętla z warunkiem wejścia, co oznacza że warunek sprawdzany jest przed każdym jej obiegiem (także pierwszym).

Zazwyczaj zechcesz gdzieś wewnątrz pętli zmieniać wartości zmiennych tak, aby warunek wejścia stał się fałszywy :)


Przykład
Obliczanie silni za pomocą pętli while – porównaj z programem wykonującym to samo zadanie z użyciem pętli for.

#include <stdio.h>
 
int main()
{
    int s, n, i;
 
    printf("Podaj liczbe naturalna n: ");
    scanf("%d", &n);
 
    s = 1;
    i = 1;
 
    while (i <= n) {
        s = s * i;
        i = i + 1;
    }
 
    printf("%d! = %d\n", n, s);
 
    return 0;
}

Która pętla Twoim zdaniem lepiej nadaje się do tego zadania?

Dobra praktyka programistyczna mówi:
Stosuj pętlę for tylko wtedy, gdy dokonujesz zarówno inicjalizacji, jak i aktualizacji. We wszystkich innych przypadkach lepiej (czytelniej) użyć pętli while.


Zadanie 1
Napisz program obliczający wynik $n \cdot k$ dla zadanych liczb całkowitych $n$ i $k$ bez korzystania z mnożenia. Użyj pętli while.
Wskazówka: $n \cdot k = \underbrace{n + n + \ldots + n}_{k \text{ razy}}$

Pętla "do-while"

Pętla do-while, podobnie jak pętla while wykonuje instrukcję dopóki spełniony jest warunek testowy.

Ogólna postać:

do
    instrukcja
while (wyrażenie_testowe);

:!: Zwróć uwagę na średnik występujący po while (...)!

Różnica między dwoma typami pętli while polega na tym, że do-while to pętla z warunkiem wyjścia – oznacza to, że warunek sprawdzany jest po każdym obiegu pętli (a więc petla wykona się co najmniej raz).


Przykład

#include <stdio.h>
 
int main(void)
{
    int i = 0;
 
    printf("Poczatek petli \n\n");
 
    do {
        printf("Wartosc zmiennej 'i' wynosi %d \n", i);
        i = i + 1;
    } while (i < 5);
 
    printf("\nKoniec petli");
 
    return 0;
}

W praktyce programiści starają się unikać stosowania do-while, gdyż:

  • umieszczanie warunku na końcu pętli zmniejsza czytelność kodu, natomiast
  • bez trudu można tak zmienić kod, aby zastąpić pętlę do-while pętlą while.

Uogólnienie powyższej zasady brzmi:
Lepiej stosować pętle z warunkiem wejścia (while, for), a nie wyjścia (do-while).   (z tych samych powodów, co podane powyżej)


Zadanie 1
Napisz program, który prosi użytkownika o podanie liczby całkowitej większej od $0$. Program powinien zakończyć działanie dopiero wtedy, gdy użytkownik podał poprawną wartość.

Zadanie 2
Napisz program losujący liczbę z przedziału $\langle 0, 100 \rangle$ tak długo aż wylosuje liczbę z przedziału $\langle 10, 15 \rangle$.
Do losowania liczb służy funkcja rand() z biblioteki stdlib.h.

Debugging

Zapoznaj się z materiałem dostępnym tu: Debugging

Zadania podsumowujące

Zadanie DIGSUM

(poziom trudności: )

Napisz program, który dla zadanej liczby całkowitej obliczy sumę jej cyfr.
Przykład: dla $196$ poprawnym wynikiem jest $1 + 9 + 6 = 16$

Wskazówka: Wykorzystaj własność dzielenia i obcięcia w języku C.

Zadanie BABSQRT

(poziom trudności: )

Napisz program obliczający pierwiastek kwadratowy zadanej liczby metodą babilońską (kroki 1-3). Przerwij obliczenia, gdy różnica między kolejnymi przybliżeniami jest mniejsza niż $10^{-4}$.

Wskazówka: Jako pierwsze oszacowanie możesz przyjąć $\sqrt{S} \approx S$ ;-)

Być może zastanawiasz się: Po co ręcznie obliczać pierwiastek? Przecież można skorzystać z wbudowanej funkcji sqrt()!
Owszem, lecz jeśli nie potrzebujesz mega-dużej dokładności, to metodą babilońską uzyskasz wystarczająco dobry wynik o wiele, wiele szybciej.

dydaktyka/cprog/2016/loops.1475432049.txt.gz · Last modified: 2020/03/25 11:46 (external edit)