LEKCJA 6 - PĘTLE FOR, WHILE I DO-WHILE

Znasz już podstawowe typy zmiennych i umiesz używać rekordów. Wiesz zatem już prawie wszystko o pisaniu bazy danych. Brakuje Ci jeszcze tylko niewielkiej informacji o tym, jak zoptymalizować operacje na wielu rekordach jednocześnie. W przykładzie wykorzystamy typ rekordowy uczen poznany na poprzedniej lekcji. Spróbujmy wpisać do bazy informacje o wszystkich uczniach:

#include <stdio.h> 
#include <conio.h> 
main (void) 
{ 
struct {
char *imie, *nazwisko; 
int numer; 
float srednia; 
}uczen[29]; 

clrscr(); 

printf("Podaj imię pierwszej osoby\n");
scanf("%s",&uczen[0].imie);
printf("Podaj nazwisko pierwszej osoby\n");
scanf("%s",&uczen[0].nazwisko);
printf("Podaj numer pierwszej osoby\n");
scanf("%d",&uczen[0].numer);
printf("Podaj średnią pierwszej osoby\n");
scanf("%f",&uczen[0].srednia);

printf("Podaj imię drugiej osoby\n");
scanf("%s",&uczen[1].imie);
printf("Podaj nazwisko drugiej osoby\n");
scanf("%s",&uczen[1].nazwisko);
printf("Podaj numer drugiej osoby\n");
scanf("%d",&uczen[1].numer);
printf("Podaj średnią drugiej osoby\n");
scanf("%f",&uczen[1].srednia);

printf("Podaj imię trzeciej osoby\n");
scanf("%s",&uczen[2].imie);
printf("Podaj nazwisko trzeciej osoby\n");
scanf("%s",&uczen[2].nazwisko);
printf("Podaj numer trzeciej osoby\n");
scanf("%d",&uczen[2].numer);
printf("Podaj średnią trzeciej osoby\n");
scanf("%f",&uczen[2].srednia);

getch(); 
return 0 ; 
} 

Jak widać, wypisanie zapytania o dane trzech pierwszych uczniów jest pracochłonne i sporo wydłuża kod programu. Gdybyśmy zapytali się o każdego z trzydziestu uczniów, kod wydłużyłby się niemiłosiernie. Łatwo byłoby się w nim zagubić.

Istnieje prosty sposób, aby czynności wykonywane wiele razy zgrupować. Służy do tego pętla for. Pozwala ona powtórzyć pewne czynności określoną ilość razy. Dla naszej bazy czynność zapytania o imię czy nazwisko musi powtórzyć się 30 razy. Gdyby nie pętla for byłoby to bardzo pracochłonne przedsięwzięcie.

Ponieważ pętla ma powtórzyć pewien ciąg instrukcji wiele razy, musimy utworzyć pewien licznik, który zliczy ile razy zadanie zostało już wykonane. Przy użyciu instrukcji for i licznika będzie więc trzeba zaznaczyć pewne warunki:

Zmodyfikujmy teraz nasz poprzedni program:

#include <stdio.h> 
#include <conio.h> 
main (void) 
{ 
int licznik;
struct {
char *imie, *nazwisko; 
int numer; 
float srednia; 
}uczen[29]; 

clrscr(); 

for(licznik=0;licznik<=29;licznik++)
{
printf("Podaj imię osoby nr: %d\n",licznik);
scanf("%s",&uczen[licznik].imie);
printf("Podaj nazwisko osoby nr %d\n",licznik);
scanf("%s",&uczen[licznik].nazwisko);
printf("Podaj numer osoby nr %d\n",licznik);
scanf("%d",&uczen[licznik].numer);
printf("Podaj średnią osoby nr %d\n",licznik);
scanf("%f",&uczen[licznik].srednia);
} 

getch(); 
return 0 ; 
} 

Użyliśmy zapisu: for(licznik=0;licznik<=29;licznik++) {instrukcje...}. Tak dosłownie tłumaczy się ten zapis:

Tak napisany program 30 razy zapyta nas o te same dane różnych osób i przypisze je do wirtualnej bazy. Jako ćwiczenie proponuję dokończyć program: użyć pętli for do wypisania wszystkich danych z bazy na ekran.


Podsumowując:

  1. Instrukcji for używamy, jeżeli chcemy wykonać kilka instrukcji określoną ilość razy.
  2. Przy użyciu instrukcji for należy ustawić warunki na licznik: stan początkowy, warunek wykonywania pętli i wartość o jaką zmienia się wartość licznika po wykonaniu pętli.
  3. Licznik jest to dodatkowa zmienna typu int.
  4. Licznik nie musi byc zwiększany, równie dobrze może liczyć w odwrotną stronę.
  5. Licznik nie musi zmieniać się o 1, lecz o dowolną wartość, aczkolwiek pierwszy przypadek jest częściej wykorzystywany w praktyce


Instrukcja for jest bardzo wygodna, ale ma jedną wadę: trzeba z góry wiedzieć, ile razy zostanie wykonana. Może o tym decydować inna zmienna, ale zawsze trzeba ją określić przed pierwszym wykonaniem pętli. Czasami zależy nam jednak w programie na tym, aby przerwać działanie pętli w momencie, kiedy pewien warunek przestanie być spełniany, ale nie wiadomo, kiedy to nastąpi. Np. program dotąd pyta użytkownika o odpowiedź, aż ten odpowie poprawnie.

Pętle, o których mowa to while i do-while. Różnią się one bardzo niewiele od siebie, ale wykazują sporo różnic w porównaniu z pętlą for. Po pierwsze: nie zawierają zmiennej sterującej, czyli licznika, który określał, ile razy pętla została wykonana (nic nie stoi jednak na przeszkodzie, aby taki licznik sobie tam umieścić, jeśli zajdzie taka potrzeba). Pora na przykład:

#include <stdio.h> 
#include <conio.h> 
main (void) 
{ 
int odp;

clrscr(); 
while(odp!=7344)
{
printf("Ile jest 153 razy 48?\n");
scanf("%d",&odp);
if (odp<7344) printf("Spróbuj jeszcze raz (wynik jest większy)");
else
if (odp>7344) printf("Spróbuj jeszcze raz (wynik jest mniejszy)");
else
printf("Dobrze!");
}

getch(); 
return 0 ; 
} 

Ekran po wykonaniu programu mógłby wyglądać tak:

Ile jest 153 razy 48?
5000
Spróbuj jeszcze raz (wynik jest większy)
Ile jest 153 razy 48?
10000
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7000
Spróbuj jeszcze raz (wynik jest większy)
Ile jest 153 razy 48?
8000
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7500
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7344
Dobrze!

W przykładzie warunkiem na to, aby pętla się wykonywała jest zła odpowiedź na pytanie. W momencie kiedy warunek ten przestanie być spełniany (użytkownik poda prawidłową odpowiedź) pętla zostanie zakończona. Zauważmy, że warunek sprawdzany jest jeszcze przed wykonaniem pętli! Może się więc zdarzyć, że pętla nie zostanie wykonana ani razu.

Ten sam program można napisać przy użyciu pętli do-while:

#include <stdio.h> 
#include <conio.h> 
main (void) 
{ 
int odp;

clrscr(); 
do {
printf("Ile jest 153 razy 48?\n");
scanf("%d",&odp);
if (odp<7344) printf("Spróbuj jeszcze raz (wynik jest większy)");
else
if (odp>7344) printf("Spróbuj jeszcze raz (wynik jest mniejszy)");
else
printf("Dobrze!");
} while(odp!=7344)

getch(); 
return 0 ; 
} 

Działanie programu będzie na pozór identyczne. Różnica polega jednak na tym, że najpierw zostanie wykonane ciało pętli (instrukcje, które mają się powtarzać), a dopiero później sprawdzony zostanie warunek. Oznacza to, że taka pętla zawsze wykona się przynajmniej raz.

Dla programu z naszego przykładu nie ma znaczenia, której z tych pętli użyjemy. Gdybyśmy jednak jeszcze przed samą pętlą przypisali do zmiennej odp wartość 7344, dopiero zauważylibyśmy różnicę. W pierwszym przypadku pętla nie uruchomiłaby się ani razu, ponieważ program najpierw sprawdza warunek, a potem dopiero przechodzi do wykonania pętli. W drugim przypadku program najpierw zapytałby nas o podanie prawidłowego wyniku. Podaną odpowiedź przypisałby do zmiennej odp i dopiero sprawdził warunek. Działanie programu w drugim przypadku nie zmieniłoby się.

Kiedy używać while a kiedy do-while? Wybór należy do programisty, który sam powinien ocenić, która będzie bardziej przydatna. Ja osobiście cześciej używam do-while.


Podsumowując:

  1. Pętlę for stosujemy, gdy wiemy ile razy ma się ona powtórzyć.
  2. Pętle while i do-while stosujemy, gdy powtarzanie pętli chcemy uzależnić od spełnienia pewnego warunku i nie wiemy ile razy będzie trzeba ja powtórzyć.
  3. Pętla while najpierw sprawdza warunek, więc instrukcje w niej zawarte mogą nigdy nie zostać wykonane.
  4. Pętla do-while najpierw wykonuje instrukcje, a potem sprawdza warunek, więc instrukcje zostaną wykonane co najmniej raz.


Autorem Kursu C++ jest Anna Miedzianowska (http://annamiedzianowska.republika.pl/).


Baner reklamowy: