Dr inż. Robert Wójcik
E-mail: wojcik@ict.pwr.wroc.pl
Języki i metody programowania
5. Instrukcje iteracyjne 5.1. Pętla for ... to („dla”)
5.2. Pętla for ... downto („dla”) 5.3. Pętla while („dopóki”)
5.4. Pętla repeat („wykonuj aż do”) 5.5. Pętle zagnieżdżone
5.6. Instrukcje sterujące przebiegiem programu
break
continue.
5. Instrukcje iteracyjne
Iteracja – cykliczne wykonywanie sekwencji rozkazów.
Aby zaprojektować iterację należy określić:
ciąg instrukcji, które mają być powtarzane,
warunek kontynuowania lub zakończenia tego ciągu.
Pętle są istotne dla wykonywania cyklicznych zadań takich jak powtarzanie sekwencji instrukcji lub dostęp do elementów tablicy.
W ogólnym przypadku można wyróżnić trzy rodzaje pętli:
o ustalonej ilości przebiegów – powtarzają pewne instrukcje określoną liczbę razy;
warunkowe – powtarzają pewne instrukcje dopóki sprawdzany warunek jest prawdziwy lub dopóki sprawdzany warunek jest fałszywy;
nieskończone – pętle otwarte, powtarzają pewne instrukcje
w nieskończoność (posiadają mechanizm opuszczenia pętli).
5.1. Pętla for ... to
Instrukcja for ... to tworzy pętlę, w której grupa instrukcji jest powtarzana określoną liczbę razy.
for zm_ster:=wyr1 to wyr2 do begin
instr_1;
instr_2;
...
instr_k; { sekwencja instrukcji } end;
zm_ster – zmienna sterująca pętli; zmienna dowolnego typu porządkowego, np. integer, longint, char;
wyr1, wyr2 - wyrażenia zgodne z typem zmiennej sterującej zm_ster;
wyr1 – wyrażenie określające wartość początkową zm_ster;
wyr2 – wyrażenie określające wartość końcową zm_ster.
W szczególności można powtarzać tylko jedną instrukcję.
for zm_ster:=wyr1 to wyr2 do instrukcja;
Przykłady prostych pętli.
Var i: integer;
z: char;
for i:=1 to 10 do { i – zmienna sterująca; wyr1=1; wyr2=10 } begin
writeln(i); { wydruk liczb od 1 do 10 } readln; { oczekiwanie na enter } end;
for i:=1 to 5 do writeln(i); { wydruk liczb od 1 do 5 }
for z:=’a’ to ’h’ do writeln(z); { wydruk znaków od a do h } Algorytm działania pętli for ... to
W pętli tej instrukcje instr_1 do instr_k są powtarzane dla kolejnych wartości zmiennej sterującej począwszy od wartości wyr1 do wartości wyr2.
Wartości wyrażeń wyr1 i wyr2 są obliczane jeden raz, przed rozpoczęciem wykonywania pętli. Jeśli wyr1 > wyr2, to instrukcje wewnętrzne pętli nie będą wykonane ani razu. Jeśli wyr1 <= wyr2, to realizowane są wewnętrzne instrukcje pętli. W każdym kroku wartość zmiennej sterującej jest modyfiko- wana automatycznie zgodnie z zależnością:
zm_ster:= SUCC(zm_ster);
gdzie funkcja SUCC(x) wyznacza następnika wartości x w ramach typu porządkowego. W przypadku, gdy x jest liczbą całkowitą instrukcja SUCC(x) jest równoważna ze zwiększeniem wartości x o jeden, tj. x: = x + 1.
Po każdej iteracji, po napotkaniu dyrektywy end w pętli lub po napotkaniu średnika, następuje sprawdzenie warunku końca pętli w postaci:
if (zm_ster = wyr2) then koniec_pętli else zm_ster:=SUCC(zm_ster);
Pętla jest powtarzana dopóki wartość zmiennej sterującej zm_ster <= wyr2.
Jeśli na końcu pętli zachodzi zm_ster = wyr2, to następuje koniec pętli.
W zakresie pętli nie zaleca się modyfikowania zmiennej sterującej. Jeśli się to zrobi, to należy uwzględnić, że wartość zmiennej zostanie dodatkowo zmieniona w ramach pętli.
Przykłady pętli rozbudowanych.
Var i, k: integer;
k:=0;
for i:= 1 to 10 do { zliczanie ilości liczb parzystych } if (i mod 2 = 0) then begin writeln(i); inc(k); end;
Var x, s : real;
i, w : longint;
w:=1; { obliczenie iloczynu: 1 x 2 x ... x 10 = 10! } for i:=1 to 10 do w:= w i;
s:=0; { obliczenie sumy: 1 + 2 + ... + 10 } for i:=1 to 10 do s:= s + i;
s:=0; x:=0.1; { obliczenie sumy: 0.1 + 0.2 + ... + 1.0 } for i:=1 to 10 do
begin
s:= s + x i; writeln(s);
end;
Pętla pusta
Pętla for może być pusta (kończy się średnikiem). Wykonanie takiej pętli prowadzi jedynie do modyfikacji zmiennej sterującej.
for i:=5 to 10 do ; { pusta pętla for }
Po osiągnięciu przez i wartości 10 następuje koniec pętli.
Przykład 5.1. Obliczanie n! . Var i,n : integer;
silnia: real;
begin
clrscr; silnia:=1;
writeln(’Podaj n z zakresu [1..20]:’);
readln(n);
if (n >0) and (n <=20) then begin
for i:=1 to n do silnia:=silnia*i;
writeln(n,’!= ’, silnia);
end else
writeln(’Liczba n jest spoza zakresu ’);
readln;
end.
Przykład 5.2. Wyprowadzanie liczb na ekran wierszami.
Var a, i, j :integer;
begin
clrscr; randomize;
{ wyprowadzanie wierszami – 4 wiersze po 8 liczb w wierszu } for i:=1 to 32 do
begin
a:= random(100);
if (i mod 8 > 0) then write(a : 3) else writeln(a : 3);
end;
end.
5.2. Pętla for ... downto
Instrukcja for ... downto tworzy pętlę, w której grupa instrukcji jest powtarzana określoną liczbę razy – podobnie jak w przypadku instrukcji for ... to.
W rozpatrywanej pętli zmienna sterująca zmienia się jednak w inny sposób, tj.
począwszy od większych wartości porządkowych do mniejszych.
for zm_ster:=wyr1 downto wyr2 do begin
instr_1;
instr_2;
...
instr_k; { sekwencja instrukcji } end;
zm_ster – zmienna sterująca pętli; zmienna dowolnego typu porządkowego, np. integer, longint, char;
wyr1, wyr2 - wyrażenia zgodne z typem zmiennej sterującej zm_ster;
wyr1 – wyrażenie określające wartość początkową zm_ster;
wyr2 – wyrażenie określające wartość końcową zm_ster.
W szczególności można powtarzać tylko jedną instrukcję.
for zm_ster:=wyr1 downto wyr2 do instrukcja;
Przykłady prostych pętli.
Var i: integer;
z: char;
for i:=10 downto 1 do { i – zmienna sterująca; wyr1=10; wyr2=1 } begin
writeln(i); { wydruk liczb od 10 do 1 } readln; { oczekiwanie na enter } end;
for i:=5 downto 1 do writeln(i); { wydruk liczb od 5 do 1 }
for z:=’h’ downto ’a’ do writeln(z); { wydruk znaków od h do a }
Algorytm działania pętli for ... downto
W pętli tej instrukcje instr_1 do instr_k są powtarzane dla kolejnych wartości zmiennej sterującej począwszy od wartości wyr1 do wartości wyr2.
Wartości wyrażeń wyr1 i wyr2 są obliczane jeden raz, przed rozpoczęciem wykonywania pętli. Jeśli wyr1 < wyr2, to instrukcje wewnętrzne pętli nie będą wykonane ani razu. Jeśli wyr1 >= wyr2, to realizowane są wewnętrzne instrukcje pętli. W każdym kroku wartość zmiennej sterującej jest modyfiko- wana automatycznie zgodnie z zależnością:
zm_ster:= PRED(zm_ster);
gdzie funkcja PRED(x) wyznacza poprzednika wartości x w ramach typu porządkowego. W przypadku, gdy x jest liczbą całkowitą instrukcja PRED(x) jest równoważna ze zmniejszeniem wartości x o jeden, tj. x: = x - 1.
Po każdej iteracji, po napotkaniu dyrektywy end w pętli lub po napotkaniu średnika, następuje sprawdzenie warunku końca pętli w postaci:
if (zm_ster = wyr2) then koniec_pętli else zm_ster:=PRED(zm_ster);
Pętla jest powtarzana dopóki wartość zmiennej sterującej zm_ster >= wyr2.
Jeśli na końcu pętli zachodzi zm_ster = wyr2, to następuje koniec pętli.
W zakresie pętli nie zaleca się modyfikowania zmiennej sterującej. Jeśli się to zrobi, to należy uwzględnić, że wartość zmiennej zostanie dodatkowo zmieniona w ramach pętli.
Przykłady pętli rozbudowanych.
Var s : real;
i, w : longint;
w:=1; { obliczenie iloczynu: 10 x 9 x ... x 1 = 10! } for i:=10 downto 1 do w:= w i;
s:=0; { obliczenie sumy: 10 + 9 + ... + 1 } for i:=10 downto 1 do s:= s + i;
5.3. Pętla while („dopóki”)
Pętla warunkowa while ma następującą składnię:
while (wyr) do begin
{ <sekwencja instrukcji>; } end;
while (wyr) do instrukcja;
Wyrażenie warunkowe wyr jest dowolnym wyrażeniem zgodnym z typem boolean. Jest ono obliczane przed wykonaniem instrukcji pętli. Jeśli wyrażenie jest fałszywe, to instrukcje pętli while nie zostaną wykonane. Zmienne sterujące pętlą muszą być modyfikowane przez programistę.
Var zn: char;
i: integer;
s: real;
zn:=’x’;
while (zn <> ’k’) do zn:= readkey; { oczekiwanie na ’k’ } i:=0; { wyprowadzanie liczb od 0 do 9 }
while (i < 10) do begin
writeln(i);
inc(i); { i:= i+1 } end;
i:=0; { wyprowadzanie 0, 3, 6, 9 } while (i < 10) do
begin
writeln(i);
i:= i+3; { przyrost i o 3 } end;
i:=9; { wyprowadzanie liczb od 9 do 0 } while (i >= 0) do
begin writeln(i);
dec(i); { i:= i -1 } end;
s:=0; i:=1; { obliczanie sumy: 1 + 2 + ... + 10 } while (i<=10) do
begin s:= s + i;
i:= i+1;
end;
Przykład 5.3. Wprowadzanie znaków i liczb w pętli Var zn: char
koniec: integer;
x: real;
ww: boolean;
begin { wprowadzanie znaków w pętli } koniec:=0;
clrscr;
while koniec<>1 do begin
writeln(’Wpisz znak (N - koniec) : ’);
readln(zn);
if (zn = 'n') or (zn = 'N') koniec = 1 else writeln(zn);
end;
x:=0; { oczekiwanie na liczbę z przedziału [5, 20] } while (x<5.0) or (x>20.0) do
begin
writeln(’Podaj liczbe z przedzialu [5,20]: ’);
readln(x);
end;
ww:= false; { oczekiwanie na liczbę z przedziału [5, 20] } while not (ww) do
begin
readln(x);
ww:= (x>=5.0) and (x<=20.0); { znaleziono – ww:=true } end;
readln;
end.
5.4. Pętla repeat („wykonuj aż do”)
Pętla warunkowa repeat ma następującą składnię:
repeat
{ <sekwencja instrukcji>; } until (wyr);
repeat instrukcja; until(wyr);
Wyrażenie warunkowe wyr jest dowolnym wyrażeniem zgodnym z typem boolean. Jest ono obliczane na końcu instrukcji pętli. Jeśli wyrażenie jest prawdziwe, to instrukcje pętli repeat nie zostaną wykonane.
Var zn: char;
i: integer;
s: real;
zn:=’x’;
repeat zn:= readkey; until (zn=’k’); { oczekiwanie na ’k’ } i:=0; { wyprowadzanie liczb od 0 do 9 }
repeat writeln(i);
inc(i); { i:= i+1 } until (i>=10);
i:=0; { wyprowadzanie 0, 3, 6, 9 } repeat
writeln(i);
i:= i+3; { przyrost i o 3 } until (i>=10);
i:=9;
repeat { wyprowadzanie liczb od 9 do 0 } writeln(i);
dec(i); { i:= i -1 } until (i<0);
s:=0; i:=1; { obliczanie sumy: 1 + 2 + ... + 10 } repeat
s:= s + i; i:= i+1;
until (i>10);
5.5. Pętle zagnieżdżone
Pętle mogą być wielokrotnie zagnieżdżane.
Przykład 5.4. Wyprowadzanie liczb na ekran wierszami.
Var a, i, j :integer;
begin { wyprowadzanie wierszami – 4 wiersze po 8 liczb w wierszu; 2 pętle } clrscr; randomize;
for i:=1 to 4 do begin
for j:=1 to 8 do begin
a:= random(100); write(a: 3);
end;
writeln;
end;
readln;
end.
Przykład 5.5. Wyprowadzanie figur o wysokości i podstawie h.
X X h XX XX h
XXX XXX Var
i,j, x,y, h :integer;
begin
clrscr; x:=1; y:=1; h:=7;
for i:=1 to h do begin
gotoxy(x, y+i);
for j:=1 to i do write('X');
end;
x:=20; y:=1;
for i:=1 to h do begin
gotoxy(x-i, y+i);
for j:=1 to i do write('X');
end;
readln;
end.
Można również zrealizować poprzedni przykład bez korzystania z procedury gotoxy. W tym celu dla pierwszego trójkąta drukujemy w jednym wierszu i znaków ’X’ oraz (h-i) spacji. Dla drugiego trójkąta drukujemy najpierw (h-i) spacji, a następnie i znaków ’X’.
uses crt;
var i, j, x, y, h: integer;
begin clrscr;
x:=1; y:=1; h:=7;
for i:=1 to h do begin
for j:=1 to i do write('X');
for j:=1 to h-i do write(' ');
writeln;
end;
readln;
x:=20; y:=1; h:=7;
for i:=1 to h do begin
for j:=1 to h-i do write(' ');
for j:=1 to i do write('X');
writeln;
end;
readln;
end.
5.6. Instrukcje sterujące przebiegiem programu Procedura Break
Procedura Break umożliwia przerwanie procesu iteracji. Wywołanie Break powoduje zakończenie pętli i przejście do wykonania kolejnych instrukcji.
Procedura może być stosowana dla każdej ze znanych rodzajów iteracji (for, repeat, while).
while wyr do begin
instr1;
instr2;
if wyr_1 then Break; { skok za end do nast_instrukcje } instr3;
...
instrN;
end;
nast_instrukcje;
W przypadku, gdy wyr_1 jest prawdziwe pętla jest przerywana. Realizowane są operacje określone przez nast_instrukcje.
Przykład 5.6. Poszukiwanie losowej liczby całkowitej należącej do przedziału [40, 50]. Liczby są losowane z przedziału [0,100].
Procedure Wypisz;
Var i: word;
Begin i:=0;
{ inicjacja generatora w programie głównym - randomize } while true do { pętla nieskończona }
begin
i:= random(101);
writeln(i);
if (i >=40) and (i<=50) then Break;
end.
End;
Procedura Continue
Procedura Continue umożliwia pominięcie instrukcji wykonywanych w pętli.
Pomijane są wszystkie instrukcje występujące w pętli po instrukcji Continue.
Procedura może być stosowana dla każdej ze znanych rodzajów iteracji (for, repeat, while). W przypadku pętli for automatycznie przyjmowana jest następna wartość licznika pętli.
while wyr do begin
instr1;
instr2;
if wyr_1 then Continue; { skok na początek pętli - while } instr3;
...
instrN;
end;
W przypadku, gdy wyr_1 jest prawdziwe instrukcje instr3 do instrN są pomi- jane. Rozpoczyna się kolejna iteracja pętli.
Przykład 5.7. Wyprowadzanie na ekran losowych liczb nieparzystych należących do przedziału [0, 100]. Liczba prób 70.
Procedure Wypisz;
Var i, n: word;
Begin
i:=1; n:=1;
{ inicjacja generatora w programie głównym - randomize } while n<=70 do { liczba prób }
begin inc(n);
i:= random(101);
if (i mod 2 = 0) then Continue; { liczba parzysta – nie pisz } writeln(i); { pisz liczbę nieparzystą }
end;
End;