User Tools

Site Tools


dydaktyka:cprog:2016:loops

This is an old revision of the document!


Pętla for, pętla "while", debuggowanie

Cel laboratorium

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

Pętla "for"

Pętla for (ang. dla) pozwala na wykonywanie fragmentu programu określoną ilość razy.

Wykorzystuje ona trzy wyrażenia rozdzielone średnikami:

  • inicjalizacja licznika – wykonywane jeden raz, zaraz przed pierwszą iteracją (obiegiem pętli)
  • warunek (test) – obliczany przed każdym potencjalnym wykonaniem pętli (jeśli wyrażenie to jest fałszywe, pętla zostaje zakończona)
  • zmiana (aktualizacja) – obliczane na końcu każdej iteracji

Pętla for kończy się jedną instrukcją prostą lub złożoną.

Pętla for to “pętla z warunkiem wejścia”, co oznacza że pętla może nie wykonać się ani razu, jeśli na samym początku warunek nie został spełniony.

Ogólna postać pętli for:

for (inicjalizacja; test; aktualizacja)
    instrukcja

Schemat blokowy a kod w C

Schemat blokowy Kod w C
int licz;
for (licz = WP; licz <= WK; licz = licz + 1) {
    instrukcja
}

Zwróć uwagę, że w języku C pętla for wykonuje się dopóki warunek jest spełniony (na sąsiednim schemacie blokowym mamy iterację dopóki warunek nie był spełniony).


Przykład 1 – Wielokrotne wypisywanie na ekran

#include <stdio.h>
 
int main()
{
    int i;
 
    for(i = 1; i <= 10; i = i + 1) {
        printf("%d\n", i);
    }
 
    return 0;
}

Przykład 2 – Obliczanie silnii

silnia.c
#include <stdio.h>
 
int main()
{
    int s, n, i;
 
    printf("Podaj liczbę naturalną n: ");
    scanf("%d", &n);
 
    s = 1;
    for(i = 2; i <= n; i = i + 1) {
        s = s * i;
    }
 
    printf("%d! = %d\n", n, s);
 
    return 0;
}

Zadanie FOR-1
Napisz program, który oblicza sumę liczb całkowitych z zakresu od 1 do 10 przy pomocy pętli for.
Oczekiwany wynik: 55

Zadanie FOR-2
Napisz program, który wczytuje zadane przez użytkownika dwie liczby całkowite – $a$ i $b$ – i oblicza sumę liczb całkowitych z przedziału $\langle a, b \rangle$. Przyjmij, że $a \leq b$ (nie sprawdzaj tego w programie).
Przykład: Dla liczb $a = 3, b = 5$ poprawnym wynikiem jest $3+4+5=12$.

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.

Podobnie jak w matematyce, w języku C możesz w wyrażeniach używać nawiasów, aby obliczenia były wykonywane w odpowiedniej kolejności.

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 PRIOR-1
Jaką wartość przyjmuje w języku C wyrażenie 3 < x < 6 dla $x = 2$? Dlaczego?

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 WHILE-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 DOWHILE-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 DOWHILE-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 BOX

(poziom trudności: )

Napisz program, który dla zadanej liczby naturalnej $n$ wyświetla “pudełko” o krawędzi długości $n$.

Przykład dla $n = 10$:

**********
**       *
* *      *
*  *     *
*   *    *
*    *   *
*     *  *
*      * *
*       **
**********

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 PRIME

(poziom trudności: )

Napisz program sprawdzający w naiwny sposób (czyli: najprostszy), czy zadana przez użytkownika liczba jest liczbą pierwszą.
Wykorzystaj pętlę for i operator modulo (%).

Wskazówka 1: Najpierw zastanów się, jakie warunki musi spełniać liczba, aby była pierwsza (inaczej: jak “ręcznie” sprawdzić, czy liczba jest pierwsza).
Wskazówka 2: Przy konstruowaniu warunku pętli bądź instrukcji warunkowych pomocne mogą Ci być prawa De Morgana.

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.

Zadanie SQUARE

(poziom trudności: )

Napisz program, który wypisze na ekran taki fragment:

1 2 3
2 3 1
3 1 2

Użyj pętli for.

Wskazówka 1: Pętle, podobnie jak instrukcje warunkowe, można zagnieżdżać. Pętla wewnętrzna wykonuje swój pełny zakres powtórzeń w każdym cyklu pętli zewnętrznej.
Wskazówka 2: Przydatny może być operator “modulo”…

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