Pętla repetycyjna (pętla warunkowa) w programowaniu, to rodzaj pętli, w której wykonanie kolejnej iteracji uzależnione jest od pewnego, zdefiniowanego przez programistę warunku. Warunek zawarty w definiowanej pętli jest pewnym wyrażeniem, które zwraca wartość typu logicznego (np. Pascal[1][2], Visual Basic[3], VBA[4]). Istnieją języki programowania, w których składnia nie przewiduje takiego typu danych. W językach tych stosuje się wyrażenia zwracające pewną wartość innego typu, która następnie podlega odpowiedniej interpretacji, np. wartość zero może być utożsamiana z wartością false typu logicznego, a pozostałe wartości z wartością true, lub inne rozwiązania (np. PL/I[5][6], C[7][8][9][10], C++[9][11] i pochodne). W zależności do tego, czy wartość logiczna, uzyskana w wyniku ewaluacji wyrażenia reprezentującego warunek, jest równa wartości logicznej true (prawda), czy false (fałsz), wykonywanie pętli jest kontynuowane, bądź przerywane.

Wyrażenia warunkowe

edytuj

Jak wyżej zaznaczono, pętla repetycyjna definiowana jest za pomocą określonego wyrażenia, które określa czy ma nastąpić przejście do kolejnej iteracji, czy też ma zostać zakończone wykonywane pętli i w konsekwencji ma nastąpić przejście do kolejnej instrukcji umieszczonej za daną pętlą. Zapis wyrażenia, oraz typ wartości wyrażenia, zależny jest od składni konkretnego języka programowania. Powszechnym jest zapis wyrażeń kontrolnych analogicznie do zapisu tych wyrażeń dla instrukcji warunkowej. Szczególne znaczenie mają w tym przypadku operatory porównań, choć warunek może zostać wyrażony także całkiem inaczej, np. jako wywołanie funkcji zwracającej wartość logiczną, bądź jako identyfikator zmiennej logicznej, której wcześniej przypisano rezultat ewaluacji wyrażenia warunkowego. Powszechna jest również w językach programowania dostępność operatorów logicznych, umożliwiających budowanie warunków złożonych z kilku warunków łącznych lub alternatywnych (ewentualnie mogą w konkretnym języku być dostępne inne operatory logiczne, np. alternatywy wykluczającej czy implikacji). Ponadto operator logiczny realizujący operację negacji pozwana na rekompensatę ewentualnego braku pętli powtarzanej przy spełnieniu lub niespełnieniu warunku, gdyż zastosowanie tego operatora do podanego warunku jest równoważne zastosowaniu frazy przeciwnej.

Wybrane przypadki wyrażeń warunkowych (przykłady w Turbo Pascalu[2])
warunek złożony użycie zmiennej powtarzaj gdy warunek nie spełniony
(sprawdzany na początku pętli)
alternatywny wobec braku odpowiedniej instrukcji
while (a<b) and ((b>c) or (b>d)) do
 begin
   { instrukcje pętli }
 end;
var logic : Boolean;
begin
  repeat
    { instrukcje pętli 1 }
    logic:=(a<b) xor (b>c);
    { instrukcje pętli 2 }
  until logic;
end.
while not (a>=b) do
 begin
   { instrukcje pętli }
 end;

Warunki kontynuacji bądź zaniechania wykonywania pętli

edytuj

W różnych językach programowania stosowane są warunki, które decydują o kontynuacji wykonywania pętli lub jej przerwania, w następujący sposób:

  • pętla jest kontynuowana gdy warunek jest spełniony (true), a przerywana gdy nie (false), lub odwrotnie
  • pętla jest kontynuowana gdy warunek nie jest spełniony (false), a przerywana gdy jest spełniony (true).
Porównanie pętli i kodu z użyciem instrukcji warunkowych oraz skoku
na przykładzie języka Visual Basic[3] i VBA[4]
miejsce sprawdzania warunku przypadek kod z użyciem pętli kod "zastępczy"
sprawdzanie warunku na początku pętli powtarzaj, gdy warunek spełniony
Do While warunek
  ' treść pętli
Loop
start: If Not warunek Then Goto koniec
  ' treść pętli
Goto start
koniec: ' koniec pętli
powtarzaj, gdy warunek nie spełniony
Do Until warunek
  ' treść pętli
Loop
start: If warunek Then Goto koniec
  ' treść pętli
Goto start
koniec: ' koniec pętli
sprawdzanie warunku na końcu pętli powtarzaj, gdy warunek spełniony
Do
  ' treść pętli
Loop While warunek
start:
  ' treść pętli
If warunek Then Goto start
' koniec pętli
powtarzaj, gdy warunek nie spełniony
Do
  ' treść pętli
Loop Until warunek
start:
  ' treść pętli
If Not warunek Then Goto start
' koniec pętli

Miejsce sprawdzania warunków

edytuj

Warunki decydujące o kontynuacji lub zaprzestaniu wykonywania pętli mogą być sprawdzane:

  • na początku pętli, przed wykonaniem pierwszej instrukcji zawartej w bloku definiowanej pętli,
  • wewnątrz pętli, w jej bloku, po wykonaniu części instrukcji, a przed wykonaniem pozostałych,
  • na końcu pętli, po wykonaniu wszystkich instrukcji zawartych w bloku definiowanej pętli.

Jeżeli warunek jest sprawdzany na początku pętli, to może nastąpić taka sytuacja, że instrukcje zawarte w pętli nigdy nie zostaną wykonane. Będzie to miało miejsce w sytuacji, gdy przy pierwszym wykonaniu warunek nie będzie spełniony (lub odwrotnie, w zależności od rodzaju pętli – zobacz wyżej). Inaczej jest, gdy warunek jest sprawdzany na końcu pętli. W tym przypadku instrukcje zawarte w pętli zostaną wykonane co najmniej jeden raz. Natomiast, jeżeli warunek jest sprawdzany wewnątrz pętli mamy sytuację stanowiącą połączanie obu powyższych przypadków. Mianowicie instrukcje zapisane przed sprawdzeniem warunku, zostaną zawsze wykonane co najmniej jeden raz, a instrukcje zapisane po warunku sprawdzającym, mogą nie zostać wykonane ani jeden raz.

Porównanie wyników programu dla różnych miejsc sprawdzania spełnienia warunku w pętli repetycyjnej (przykłady w języku C[7][8][9][10])
miejsce sprawdzania warunku na początku wewnątrz na końcu
przykład
#define MIN=4
int a;
scanf("a=%d",a);
while(MIN>=a)
 {
   printf("Teraz a=%d\n\r",a++);
   printf("Teraz a=%d\n\r",a++);
 }
#define MIN=4
int a;
scanf("a=%d",a);
while(1)
 {
   printf("Teraz a=%d\n\r",a++);
   if (!(MIN>=a)) break;
   printf("Teraz a=%d\n\r",a++);
 }
#define MIN=4
int a;
scanf("a=%d",a);
do
   printf("Teraz a=%d\n\r",a++);
   printf("Teraz a=%d\n\r",a++);
while(MIN>=a)
wartość zmiennej a 1 3 5 1 3 5 1 3 5
wyniki Teraz a=1
Teraz a=2
Teraz a=3
Teraz a=4
Teraz a=3
Teraz a=4
  Teraz a=1
Teraz a=2
Teraz a=3
Teraz a=4
Teraz a=5
Teraz a=3
Teraz a=4
Teraz a=5
Teraz a=5 Teraz a=1
Teraz a=2
Teraz a=3
Teraz a=4
Teraz a=3
Teraz a=4
Teraz a=5
Teraz a=6

Zazwyczaj w danym języku programowania zdefiniowane w składni konstrukcje pętli repetycyjnych są tak określone, że jest możliwe sprawdzenie jedynie warunku albo na początku, albo na końcu pętli – nie ma w tym przypadku możliwości zdefiniowania warunków sprawdzanych zarówno na początku, jak i na końcu pętli (np. C[7][8][9][10], C++[9][11], Pascal[1][2]). Inaczej jest jednak, gdy zdefiniowana jest w języku jedna konstrukcja pętli, w której można definiować warunki za pomocą opcjonalnych fraz instrukcji, tak jak zostało to przyjęte np. w języku PL/I[5][6].

Porównanie: PL/I – C, C++
PL/I[5][6] C[7][8][9][10], C++[9][11]
DO WHILE A<B UNTIL C>B;
 /* instrukcje pętli */
 /* brak konieczności stosowania
    instrukcji warunkowej i opuszczenia
    wszystkie warunki zdefiniowane w nagłówku
    pętli za pomocą odpowiednich fraz */
END;
while(a<b)
 {
   /* instrukcje pętli */
   /* sprawdzenie dodatkowego warunku
      na końcu pętli wymaga użycia
      instrukcji warunkowej i opuszczenia */
   if(!(c>b)) break;
 }

Także rzadko występującą możliwością konstruowania pętli jest możliwość jej kontynuowania po zakończeniu bieżącego warunku, już dla innego, kolejnego warunku.

Przykład w PL/I[5][6]:

DO WHILE A<B UNTIL C>B, WHILE D<B, UNTIL D>A;
 /* instrukcje pętli */
 /* wykonanie pętli nastąpi kolejno dla 3 niezależnych warunków:
    – dla A<B (warunek sprawdzany na początku pętli) i równocześnie C>B (ale warunek sprawdzany na końcu pętli),
    – a po zakończeniu pętli dla powyższych warunków, dla D<B (warunek sprawdzany na początku pętli),
    – i następnie dla D>A (warunek sprawdzany na końcu pętli) */
END;

O sposobie i miejscu zapisu warunków sprawdzających decyduje składnia danego języka programowania. Dla warunków sprawdzanych wewnątrz bloku instrukcji definiujących kolejne iteracje, zapis zawarty jest w ciągu tych instrukcji (np. Ada[12][13], Forth[14][15]). Natomiast dla warunków sprawdzanych na początku i końcu pętli spotyka się rozwiązania, w których albo warunki zapisywane są odpowiednio w miejscu ich wykonywania, tj. na początku i na końcu (np. C[7][8][9][10], C++[9][11], Pascal[1][2], Modula-2[16], Visual Basic[3], VBA[4] i wiele innych), albo rzadziej wszystkie warunki, także te sprawdzane na końcu pętli, definiowane są na początku pętli, w jej nagłówku, w jednym miejscu określającym sposób kolejnych iteracji (np. PL/I[5][6]). W językach programowania, w których nie ma konstrukcji do sprawdzania warunku wewnątrz bloku pętli, dostępne są często instrukcje umożliwiające zmianę przebiegu wykonywania pętli, takie jak instrukcja opuszczenia czy instrukcja kontynuacji (np. C[7][8][9][10], C++[9][11]: break, continue), które stosowane w połączeniu z instrukcją warunkową lub wyboru (np. C[7][8][9][10], C++[9][11]: if, switch), zapewniają praktycznie równorzędne środki sterowania przebiegiem realizacji algorytmu.

Porównanie konstrukcji językowych z wbudowanym sprawdzeniem warunku wewnątrz pętli i
odpowiadających im konstrukcji, gdy język nie przewiduje takich fraz dla pętli
Sposób zapisu Przykłady
Sprawdzenie warunku wewnątrz pętli Ada[12][13] Forth[14][15]
loop
   -- instrukcje przed sprawdzeniem warunku
   exit when warunek;
   -- instrukcje po sprawdzeniu warunku
end loop;
-- instrukcje za pętlą
BEGIN
   ( instrukcje przed sprawdzeniem warunku )
   ( warunek ) WHILE
   ( instrukcje po sprawdzeniu warunku )
REPEAT
( instrukcje za pętlą )
Konstrukcje "zastępcze" C[7][8][9][10], C++[9][11] PL/I[5][6]
wymagane użycie
  • instrukcji warunkowej if, oraz
  • instrukcji opuszczenia break
wymagane użycie
while(1)
 {
   /* instrukcje przed sprawdzeniem warunku */
   if(warunek) break;
   /* instrukcje po sprawdzeniu warunku */
 }
/* instrukcje za pętlą */
DO WHILE '1'B;
   /* instrukcje przed sprawdzeniem warunku */
   IF warunek THEN
     GOTO LAB;
   /* instrukcje po sprawdzeniu warunku */
END;
LAB: /* instrukcje za pętlą */

Typowe konstrukcje składniowe

edytuj

Składnia poszczególnych języków programowania definiuje sposób zapisu poszczególnych elementów danego języka i jest różna w zależności od przyjętych przez jego autora rozwiązań. Spotyka się jednak w językach pewną grupę typowych, używanych słów kluczowych, które stanowią podstawę zapisu instrukcji[1][2][7][8][9] lub odpowiednich fraz instrukcji[5][6], definiujących warunki jej wykonania. Są to np.

while warunek
to słowo kluczowe stosowane w wielu językach programowania definiuje warunek, który musi być spełniony, aby pętla była wykonywana, stosowana jest zarówno na początku pętli (np. C[7][8][9], C++[9]: while(warunek) instrukcja; Pascal: while warunek do instrukcja), jak i na końcu (np. C[7][8][9], C++[9]: do instrukcje while(warunek);).
until warunek
to słowo kluczowe w różnych językach ma różne implikacje:
  • warunek który określa, iż pętla będzie powtarzana dopóki warunek nie stanie się spełniony, np. Pascal: reperat instrukcje until warunek; Visual Basic[3], VBA[4]: Do Until warunek instrukcje Loop, Do instrukcje Loop Until warunek;
  • warunek, który jest sprawdzany na końcu pętli (choć zapis warunku znajduje się na jej początku w nagłówku definiującym), a pętla jest powtarzana jeżeli warunek jest spełniony, np. PL/I[5][6]: DO UNTIL warunek; instrukcje END; (odpowiednik instrukcji do ... while(warunek); z języka C[7][8][9], C++[9]).

Przykłady pętli repetycyjnych

edytuj
Przykłady pętli repetycyjnych
spełnienie/nie spełnienie język programowania miejsce sprawdzania warunku miejsce zapisu warunku
sprawdzanego na końcu pętli
na początku pętli na końcu pętli
powtórzenie
gdy warunek spełniony
C[7][8][9][10]
C++[9][11]
while(a<MAX_A)
 {
   printf("a=%d",a++);
 }
do
   printf("a=%d",a++);
while(a<MAX_A);
na końcu
Pascal[1][2]
while a<MAX_A do
 begin
   writeln("a=",a);
   a:=a+1
 end;
   
Modula-2[16]
WHILE A<MAX_A DO
   WRITE("a=",A);
   A:=A+1
END;
   
PL/I[5][6]
DO WHILE A<MAX_A;
  CALL WRITE('A=',A);
  A=A+1;
END;
DO UNTIL A<MAX_A;
  CALL WRITE('A=',A);
  A=A+1;
END;
na początku
Visual Basic[3]
VBA[4]
Do While a<MAX_A
  Call WriteLine("a=", a)
  a=a+1
Loop
Do
  Call WriteLine("a=", a)
  a=a+1
Loop While a<MAX_A
na końcu
powtórzenie
gdy warunek nie spełniony
Do Until a=MAX_A
  Call WriteLine("a=", a)
  a=a+1
Loop
Do
  Call WriteLine("a=", a)
  a=a+1
Loop Until a=MAX_A
na końcu
Pascal[1][2]
Modula-2[16]
 
repeat
   writeln("a=",a);
   a:=a+1
until a=MAX_A;
na końcu

Pętla repetycyjna w językach programowania

edytuj
Pętle repetycyjne w językach programowania[a]
miejsce sprawdzania warunku na początku pętli wewnątrz pętli na końcu pętli
język programowania gdy warunek spełniony gdy nie spełniony gdy warunek spełniony gdy nie spełniony gdy warunek spełniony gdy nie spełniony
Ada[12][13]          [b]  
AWK[17]            
BCPL[18]            
C[7][8][9][10]
C++[9][11]
           
Clipper[19][20]            
Comal[21]            
Eiffel[22]            
Forth[c][14][15]  [b]        [b]  
MCPL[23]            
Modula-2[16]            
Pascal[1][2]            
Perl[24]          [d]  [d]
PL/I[5][6]            
PL/M[25][26]            
PL/pgSQL[27]          [b]  
Ruby[28]            
Visual Basic[3]
VBA[4]
           
  1. Uwzględniono jedynie konstrukcje językowe zdefiniowane dla pętli; nie uwzględniono konstrukcji "zastępczych", tj. wymagających użycia instrukcji warunkowych.
  2. a b c d W językach takich jak Ada, Forth, czy PL/pgSQL, warunek sprawdzający wewnątrz pętli może zostać umieszczony na samym początku lub na samym końcu pętli, i wtedy mamy do czynienia z przypadkami krańcowymi, lecz nie są to odrębne konstrukcje składniowe, a jedynie przypadki szczególne sprawdzania warunku wewnątrz pętli, w związku z czym nie zostały one uwzględnione w zestawieniu
  3. Uwzględniono standardowo dostępną konstrukcję pętli; język Forth jest językiem rozszerzalnym – można w nim zdefiniować za pomocną odpowiednich kompilatorów (rozumianych w sensie języka Forth) nowe instrukcje sterujące i strukturalne, w tym konstrukcje pętli, które odpowiadałyby pozostałym przypadkom.
  4. a b W języku Perl warunki sprawdzane na początku pętli są strukturami sterującymi, warunki sprawdzane na końcu pętli są zrealizowane jako modyfikatory.

Przypisy

edytuj
  1. a b c d e f g Michał Iglewski, Jan Madey, Stanisław Matwin: Pascal. Język wzorcowy – Pascal 360. Wyd. trzecie – zmienione. Warszawa: Wydawnictwa Naukowo-Techniczne, 1984, seria: Biblioteka Inżynierii Oprogramowania. ISBN 83-85060-53-7. ISSN 0867-6011. (pol.).
  2. a b c d e f g h Andrzej Marciniak: Borland Pascal 7.0. Poznań: Nakom, 1994, seria: Biblioteka Użytkownika Mikrokomputerów. ISBN 83-85060-53-7. ISSN 0867-6011. (pol.).
  3. a b c d e f Podręcznik Visual Basic na Wikibooks
  4. a b c d e f John Walkenbach: Excel 2003 PL. Programowanie w VBA.. HELION, 2004. ISBN 837361-504-0. (pol.).
  5. a b c d e f g h i j Jan Bielecki: Rozszerzony PL/I i JCL w systemie OS/RIAD. Warszawa: Państwowe Wydawnictwo Naukowe, 1986, seria: Biblioteka Informatyki. ISBN 83-01-06146-4. (pol.).
  6. a b c d e f g h i j M. I. Auguston i inni: Programowanie w języku PL/1 OS JS. Warszawa: Państwowe Wydawnictwo Naukowe, 1988. ISBN 83-01-07463-9. (pol.).
  7. a b c d e f g h i j k l m n Brian W. Kernighan, Dennis M. Ritche: Język C. Warszawa: Wydawnictwa Naukowo-Techniczne, 1988, seria: Biblioteka Inżynierii Oprogramowania. ISBN 83-204-1067-3. (pol.).
  8. a b c d e f g h i j k l m n Jan Bielecki: Turbo C z grafiką na IBM PC. Warszawa: Wydawnictwa Naukowo-Techniczne, 1990, seria: Mikrokomputery. ISBN 83-204-1101-7. (pol.).
  9. a b c d e f g h i j k l m n o p q r s t u v w x y z Jan Bielecki: Od C do C++, programowanie obiektowe w języku C. Warszawa: Wydawnictwa Naukowo-Techniczne, 1990. ISBN 83-204-1332-X. (pol.).
  10. a b c d e f g h i j Podręcznik języka C na Wikibooks
  11. a b c d e f g h i Podręcznik języka C++ na Wikibooks
  12. a b c A. Nico Habermann, Dewayne E. Perry: Ada dla zaawansowanych. Warszawa: Wydawnictwa Naukowo-Techniczne, 1989, seria: Biblioteka Inżynierii Oprogramowania. ISBN 83-204-1058-4. (pol.).
  13. a b c Michał Morawski, Antoni M. Zajączkowski: Wstęp do programowania w języku Ada’95. Wyd. drugie. Łódź: 2004. [dostęp 2011-01-29]. (pol.).
  14. a b c Jan Bielecki: Język FORTH. Warszawa: Wydawnictwa Naukowo-Techniczne, 1988, seria: Mikrokomputery. ISBN 83-204-0930-6. (pol.).
  15. a b c Jan Ruszczyc: Poznajemy FORTH. Warszawa: SOETO, 1987, seria: Informatyka mikrokomputerowa. (pol.).
  16. a b c d Niklaus Wirth: Modula 2. Warszawa: Wydawnictwa Naukowo-Techniczne, 1987, seria: Biblioteka Inżynierii Oprogramowania. ISBN 83-204-0828-8. ISSN 0867-6011. (pol.).
  17. Tomasz Przechlewski: Opis języka AWK. [dostęp 2011-01-31]. (ang.).
  18. Martin Richards: The BCPL Cintsys and Cintpos User Guide. Cambridge: Computer Laboratory University of Cambridge, January 28, 2011. [dostęp 2011-01-31]. (ang.).
  19. Wojciech Rogowski, Arkadiusz Serodziński: Clipper 5.0. Warszawa: Wydawnictwo PLJ, 1991. ISBN 83-85190-20-1. (pol.).
  20. Krzysztof Walczak: Język Clipper. Warszawa: Wydawnictwa Naukowo-Techniczne, 1990, 1991, seria: Podręczna Pamięć Programisty. ISBN 83-204-1359-11. (pol.).
  21. Mike Ducka, tłumaczenie: Marcin Turski: Języki mikrokomputerów. Przewodnik dla początkujących. Basic, Pascal, Logo, Prolog, Comal, Forth. Warszawa: Wydawnictwa Naukowo-Techniczne, 1988. ISBN 83-204-0966-7. (pol.).
  22. Bertrand Meyer: Eiffel*: A Language and Environment for Software Engineering. Goleta, California: Interactive Software Engineering Inc.. [dostęp 2011-01-31]. (ang.).
  23. Martin Richards: The MCPL Programming Manual and User Guide. Cambridge: Computer Laboratory University of Cambridge, May 23, 2007. [dostęp 2011-01-31]. (ang.).
  24. Podręcznik języka Perl na Wikibooks
  25. Jan Bielecki: PL/M język programowania mikroprocesorów. Wyd. drugie uzupełnione. Warszawa: Wydawnictwa Komunikacji i Łączności, 1987, seria: Elektronizacja. zeszyt 25. (pol.).
  26. Jan Bielecki: System operacyjny ISIS-II. Warszawa: Wydawnictwa Naukowo-Techniczne, 1987, seria: Mikrokomputery. ISBN 83-204-0893-8. (pol.).
  27. PostgreSQL 8.3.13 Documentation. [dostęp 2011-01-31]. (ang.).
  28. Podręcznik języka Ruby na Wikibooks

Bibliografia

edytuj
  • Michael Marcotty, Henry Ledgord, tłumaczenie: Krystyna Jerzykiewicz: W kręgu języków programowania. Warszawa: Wydawnictwa Naukowo-Techniczne, 1980, seria: Biblioteka Inżynierii Oprogramowania. ISBN 83-204-1342-7. (pol.).
  • John E. Nicholls: Struktura języków programowania. Warszawa: Wydawnictwa Naukowo-Techniczne, 1980, seria: Informatyka. ISBN 83-204-0246-8. (pol.).
  • Mike Ducka, tłumaczenie: Marcin Turski: Języki mikrokomputerów. Przewodnik dla początkująych. Basic, Pascal, Logo, Prolog, Comal, Forth. Warszawa: Wydawnictwa Naukowo-Techniczne, 1988. ISBN 83-204-0966-7. (pol.).