6. Pętle - majsylw/Introduction-to-programming-in-C GitHub Wiki

Programowanie w dużej mierze opiera się na uogólnianiu rozwiązań problemów. A więc uogólniając, naszym zadaniem jest napisać jeden kod, który będzie wstanie rozwiązać jak najwięcej potencjalnych problemów. Za przykład możemy wziąć obliczanie średniej arytmetycznej ocen. Chcemy napisać program, który będzie umiał obliczyć średnią niezależnie od liczby ocen, jaką będzie chciał podać użytkownik. Nie chcemy kodu na sztywno zawsze obliczającego jej z 3 czy 5 liczb, ale z n liczb. Wiąże się z tym zagadnieniem problem powtarzania kodu: możemy napisać 5 razy pod rząd kod, który prosi o podanie liczby przez użytkownika, a następnie dodaje ją do sumy. Jednak jest to dokładnie tym, czego chcemy uniknąć - tutaj z pomocą przychodzą nam pętle. Zanim przejdziemy do średniej, spójrzmy na klasyczny przykład wypisywania kolejnych liczb, od 0 do 4, który pozwoli nam zrozumieć pętle. W języku C mamy trzy rodzaje pętli: while, do...while oraz for.

Pętla while

Pierwszą konstrukcją, którą chcę tutaj przytoczyć jest pętla while. Jej składnia jest następująca:

while (warunek){
    instrukcja;
}

Instrukcja zawarta wewnątrz pętli (kod wcięty pod słowem while) będzie wykonywała się tak długi jak warunek będzie spełniony. Oznacza to, że o ile nie chcemy w nieskończoność (bądź nigdy) wykonywać pewnych operacji to potrzebujemy aby zmienna wykorzystana do stworzenia warunku zmieniała swoją wartość w trakcie wykonywania się pętli (w każdym, bądź w poszczególnych, krokach - iteracjach). Zobaczmy to na prostym przykładzie:

int i = 0;
while (i < 5){
    printf("%d",i);
    i += 1;
}
// 0 1 2 3 4

Wcześniej stworzyliśmy zmienną i, przypisując jej wartość 0. Następnie w samej pętli while jest warunek: wykonuj ciało pętli dopóki wartość zmiennej i jest ostro mniejsza od 5 (w matematyce mówimy ostro gdy chcemy podkreślić, że nie dopuszczamy równości). Dopóki więc ten warunek jest spełniony, wykonujemy dwa polecenia: wypisujemy wartość zmiennej i, oraz dodajemy do niej liczbę 1. Oczywiście przy konstruowaniu warunków możemy korzystać z poznanych wcześniej operatorów logicznych i porównania, nie musimy ograniczać się do korzystania tylko z jednej zmiennej. Wewnątrz ciała pętli możemy zawrzeć dowolne instrukcje.

Pętla do...while

Kolejna pętla, którą chcę tutaj omówić jest troszeczkę urozmaiconym wariantem petli '''while'''. Jej składnia jest następująca:

do{
    instrukcje;
}while (warunek);

Podstawowa różnica polega na tym, że instrukcje wewnątrz pętli wykonywane są najpierw, a dopiero potem sprawdzany jest warunek. Oznacza to, że powyższa pętla z pewnością wykona się przynajmniej raz.

Pętla for

Kolejnym przykładem pętli używanej w języku C jest pętla for. Zobaczmy jej wykorzystanie na poniższym przykładzie:

int i;
for(i=0; i<5; i++){
    printf("%d",i);
}
// 0 1 2 3 4

Taki zapis oznacza, że ciało pętli (wcięte wiersze kodu pod słowem for) będzie wykonywać się 5 razy: za każdym razem wartość zmiennej i będzie różna: najpierw będzie to 0, potem 1, potem 2 i tak aż do 4 włącznie. Tutaj kod nie robi nic poza wypisaniem wartości zmiennej i na ekran. Przyjrzyjmy się dokładnie konstrukcji warunku w pętli for, czyli tym, co jest w nawiasach (), czyli (i=0; i<5; i++). Przed pierwszym średnikiem inicjalizujemy zmienną i, czyli nasz iterator-krok, wartością 0, potem następuje średnik oraz warunek, którzy zarządza liczbą iteracji - pętla for będzie się tak długo wykonywała jak warunek ten będzie spełniony. Ostatni człon i++ steruje zachowaniem się kroku w każdej iteracji - tutaj wartość zmiennej i zostaje zwiększona o jeden.

Możemy dostrzec pewne podstawowe różnice pomiędzy pętlami while i for, a mianowicie: w przypadku pętli for z góry podajemy liczbę wartości jakie ma przyjąć iterator, podczas gdy dla pętli while nie podajemy z góry, jakie wartości ma przyjmować zmienna i, ale za to podajemy warunek logiczny, jak długo pętla ma się wykonywać. Dla pętli while musimy sami zadbać o zmianę wartości zmiennej i wewnątrz ciała pętli, tak aby ostatecznie warunek stał się fałszywy. Na zmienną, która się zmienia w każdej iteracji pętli, w naszym przypadku jest to zmienna i, mówi się zmienna iterująca (lub krócej iterator).

Pozostaje pytanie, którą pętlę wybrać, skoro są one tak bardzo do siebie podobne? Może na tym etapie trudno wyrobić sobie jakąś intuicję, jednak generalna zasada jest następująca: pętli while używa się wtedy, gdy nie jesteśmy w stanie na etapie pisania programu powiedzieć, ile będzie iteracji pętli, gdyż ta liczba jest mocno zależna od danych wejściowych (algorytmy numeryczne, wczytywanie danych z nieznanych źródeł…), podczas gdy pętla for jest używana, gdy możemy powiedzieć, ile będzie iteracji, nawet jeśli ta odpowiedź wynosi “długość tablicy”, albo “wartość zmiennej n”.

Instrukcje sterujące

Do przerywania bieżącego wykonania pętli służą instrukcje sterujące: continue i break.

Instrukcja continue

Umieszczenie tej instrukcji sterującej wewnątrz jakiejkolwiek pętli przerywa jej działanie i powoduje przejście do wywołania kolejnej iteracji, np.

int i;
for(i=0; i<5; i++){
    if (i == 2){
        continue;
    }
    printf("%d",i);
}
// 0 1 3 4 <- w tym przypadku tylko dla i=2 instrukcja z pętli się nie wykona

Instrukcja break

Tę instrukcję poznaliśmy już przy okazji konstrukcji switch...case. Jej umieszczenie wewnątrz jakiejkolwiek pętli przerywa całkowicie jej działanie i powoduje przejście do kodu umieszczonego za nią, np.

int i;
for(i=0; i<5; i++){
    if (i == 2){
        break;
    }
    printf("%d",i);
}
// 0 1 <- tylko tyle liczb zdąży się wyświetlić