Opowieść o programowaniu w Adzie



Pobieranie 0.69 Mb.
Strona9/16
Data28.04.2016
Rozmiar0.69 Mb.
1   ...   5   6   7   8   9   10   11   12   ...   16

Instrukcje pętli

Stworzyliśmy program do obsługi wagi dla ciężarówek. No dobrze - możemy zapytać - ale czy koniecznie osoba pracująca przy tej wadze musi uruchamiać program od nowa, aby zważyc kolejny samochód? Czy nie można byłoby przerobić tego programu tak, aby po otrzymaniu wyniku znów pojawiała się plansza "menu", gdzie wybieramy markę ważonego pojazdu, a działanie programu zakańczamy przez wpisanie np. zera? Oczywiście jest to możliwe. W tym celu musimy zapoznać się z kolejnym rodzajem instrukcji, a mianowicie z instrukcjami pętli. Jest ich kilka - pętla "prosta", pętla while i pętla for. Najmniej skomplikowana jest pierwsza z nich o składni


loop

instrukcje

end loop;


Instrukcje umieszczone wewnątrz pętli będą w tym wypadku wykonywane nieskończenie wiele razy. Po dojściu do linii end loop następuje powrót do początku pętli, czyli do linii zawierającej słowo loop, kolejne wykonanie itd. Teoretycznie program zawierający taką pętlę mógłby działać nieprzerwanie. Na przykład program
with ada.text_io;

use ada.text_io;


procedure pr24 is

begin


loop

put("Ada ");

end loop;

end pr24;


będzie zapisywał ekrany słowem "Ada", dopóki nie przerwiemy jego działania klawiszami Ctrl-Break lub Ctrl-C. Jeżeli jednak wsród instrukcji wewnątrz pętli znajdzie się słowo
exit;
lub
exit warunek;
to po dojściu do tej linii (w przypadku pierwszym), lub po dojściu do tej linii i stwierdzeniu, że warunek zachodzi, nastąpi wyjście z pętli i wykonanie pierwszej z instrukcji następujących po end loop.
-- modyfikacja programu pr22

--


-- mozliwosc wielokrotnych obliczen
with ada.text_io,ada.numerics;

use ada.text_io;


procedure pr25 is

package int_io is new ada.text_io.integer_io(integer);

package flt_io is new ada.text_io.float_io(float);

use int_io, flt_io;

subtype mozliwosc is integer range 1..3;

nr:mozliwosc;

a,b:float;

odp:character;


begin
loop
put_line(" Program oblicza pola nastepujacych figur :");

set_col(10);put_line("1 : trojkat ");

set_col(10);put_line("2 : prostokat");

set_col(10);put_line("3 : kolo");

new_line;

put("Podaj numer wybranej figury : "); get(nr);

new_line;

case nr is

when 1 => put("podaj dlugosc podstawy : ");

get(a);


put("podaj dlugosc wysokosci opuszczonej na te

podstawe : ");

get(b);

new_line;



put("pole trojkata wynosi ");

put(a*b/2.0,exp=>0);

put(" j.kw");

when 2 => put_line("podaj dlugosci bokow : ");

put("a : ");get(a);

put("b : ");get(b);

new_line;

put("pole prostokata wynosi ");

put(a*b,exp=>0);

put(" j.kw");

when 3 => put("podaj promien kola : ");

get(a);


new_line;

put("pole kola wynosi ");

put(ada.numerics.pi*a**2,exp=>0);

put(" j.kw");

end case;
new_line(2);

put("czy liczymy dalej? (n - koniec) ");get(odp);

exit when odp='n';

new_line(5);


end loop;
end pr25;
Dzięki zastosowaniu powyższej pętli nie musimy wielokrotnie uruchamiać programu, jeśli chcemy obliczyc pola kilku figur. Program pyta, czy chcemy jeszcze coś obliczyć, i jeżeli wciśniemy klawisz n, zakańcza działanie. Wciśnięcie każdego innego klawisza powoduje powtórne wykonanie programu. W podobny sposób możemy zmodyfikować program pr23, co będzie rozwiązaniem przedstawionego na początku problemu.
Kolejną pętlą jest pętla while postaci
while warunek loop

instrukcje

end loop;


która jest właściwie podobna do prostej pętli zawierającej instrukcję exit. Instrukcje wewnątrz pętli wykonywane są tak długo, jak długo zachodzi warunek. Po raz pierwszy warunek sprawdzany jest jeszcze przed wejściem do pętli, a więc istnieje możliwość, że instrukcje wewnątrz niej nie będą w ogóle wykonane. Tak na przykład instrukcje wewnątrz poniższej pętli
get(a);

while a<100 loop

.....

a:=a+2;


...

end loop;


mogą nie byc wykonane, jeśli podamy a większe bądź równe 100.

Oto przykład wykorzystania tej instrukcji - program obliczający, ile kolejnych liczb całkowitych dodatnich należy zsumować, aby ich suma była większa bądź równa podanej liczbie:


-- przyklad wykorzystania petli while

-- obliczamy, ile kolejnych liczb

-- calkowitych dodatnich nalezy dodac,

-- aby ich suma byla wieksza lub rowna

-- podanej liczbie
with ada.text_io;

use ada.text_io;


procedure pr26 is

package int_io is new ada.text_io.integer_io(integer);

use int_io;

liczba,suma:integer;

n:natural;

begin


loop

put("Podaj liczbe calkowita dodatnia : ");

get(liczba);

exit when liczba>0;

put("To nie jest liczba dodatnia!!! ");

end loop;


suma:=0;n:=0;

while suma

n:=n+1;

suma:=suma+n;



end loop;

put("Zsumowalismy ");put(n,0);

if n mod 10 in 2..4 then

put(" kolejne liczby i otrzymalismy ");

else

put(" kolejnych liczb i otrzymalismy ");



end if;

put(suma,0);

end pr26;
A jeżeli chcemy, aby instrukcje wewnątrz pętli wykonały się pewną, ściśle określoną ilość razy? W tym celu możemy wykorzystać pętlę for o składni:
[1] for licznik_pętli in zakres loop

instrukcje

end loop;


albo
[2] for licznik_pętli in reverse zakres loop

instrukcje

end loop;


Program pr27 ilustruje użycie obu postaci tej pętli:
with ada.text_io;

use ada.text_io;


-- przyklad dzialania petli for
procedure pr27 is
package int_io is new ada.text_io.integer_io(integer);

use int_io;


begin
for i in 1..5 loop

put("Petla wykonuje sie po raz ");

put(i,0);

new_line;

end loop;

new_line(2);

for i in reverse 1..5 loop

put("Petla wykonuje sie dla liczby ");

put(i,0);

new_line;

end loop;
end pr27;
Wynikiem jego wykonania będzie napisanie
Petla wykonuje sie po raz 1

Petla wykonuje sie po raz 2

Petla wykonuje sie po raz 3

Petla wykonuje sie po raz 4

Petla wykonuje sie po raz 5.
Petla wykonuje sie dla liczby 5

Petla wykonuje sie dla liczby 4

Petla wykonuje sie dla liczby 3

Petla wykonuje sie dla liczby 2

Petla wykonuje sie dla liczby 1.
Jak widać, w pętli postaci [1] licznik przyjął na początku wartość 1 - dolne ograniczenie zakresu. Każde następne wykonanie pętli powoduje automatyczne zwiększenie wartości licznika o 1. Dzieje się tak dopóki licznik nie osiągnie wartości 5 - górnego ograniczenia zakresu. Pętla w postaci [2] działa w bardzo podobny sposób, ale jakby "od tyłu" - na początku licznik przyjmuje wartośc górnego ograniczenia zakresu, przy każdym przejściu pętli jest zmniejszany o 1 aż do osiągnięcia wartości dolnego ograniczenia zakresu. Licznika pętli nie musimy (i nie możemy) deklarować ani nadawać mu początkowej ani kolejnych wartości (pisząc na przykład wewnątrz pętli i:=i+1), a jeżeli w programie zadeklarowaliśmy i użyliśmy zmiennej o tej samej nazwie, to zostanie ona przesłonięta przez licznik pętli, a więc będzie wewnątrz pętli niemożliwa do użycia. Nie możemy sami zmieniac wartości licznika - napisanie np.
for i in 1..10 loop

.....


i:=5;

end loop;


jest niedozwolone (licznik jest traktowany podobnie jak stała). Jego wartość i zgodność z zakresem jest rozpatrywana na początku pętli, zatem napisanie
for i in 2..1 loop

put("Napis");

end loop;
spowoduje, że napis taki nigdy się nie ukaże, gdyż licznik przyjmie na początek wartość 2, a więc od razu przekroczy górne ograniczenie zakresu (tzn. 1). Licznik pętli może przyjmowac wartości należące do typu dyskretnego. Nie możemy napisać na przykład
for i in 1.2 .. 4.5 loop
możemy natomiast - dla zadeklarowanego wcześniej typu wyliczeniowego dni napisać
for i in pon..czw loop
albo
for i in dni loop
Widać więc, że w roli zakresu może wystąpić nazwa typu bądź podtypu.

Zakres licznika pętli nie musi byc ustalony raz na zawsze - może się zmieniać, jednak jego wartość musi być znana już przed wejściem do pętli. Można napisać na przykład


get(n);

for i in 1..n loop

...

end loop;


lub też
x:=150;

for j in 1..x loop

...

end loop;


czy

for k in 100..integer'last loop

...

end loop;


nie ma sensu natomiast
x:=3;

for i in 1..x loop

...

x:=20;


end loop;
Nie spowoduje to zgłoszenia błędu, ale pętla zostanie wykonana tylko trzy razy - zakres licznika pętli został ustalony na początku, przed wejściem do niej.
Oto kilka przykładów zastosowania pętli:
-- przyklad zastosowania petli for

-- kilkakrotne narysowanie "mordki"


with ada.text_io;

use ada.text_io;


procedure pr28 is

package int_io is new ada.text_io.integer_io(integer);

use int_io;

n:integer;

begin

put("Ile rysunkow chcesz wykonac? ");get(n);



for i in 1..n loop

put(i,0);put_line(" : ");

put_line("\\\//");

put_line(" 0 0 ");

put_line(" ~_ ");

new_line;

end loop;

end pr28;


i modyfikacja programu pr15:
-- tabelka logiczna

-- modyfikacja programu pr15

-- przyklad uzycia petli
with ada.text_io;

use ada.text_io;


procedure pr29 is

package b_io is new ada.text_io.enumeration_io(boolean);

p,q:boolean;

begin


put_line(" TABELKA WARTOSCI LOGICZNYCH");

new_line(3);

put(" | p | q | not p | p and q | p or q | p xor q |");

new_line;


for p in boolean loop

for q in boolean loop


put(" | ");b_io.put(p,width=>5);

put(" | ");b_io.put(q,width=>5);

put(" | ");b_io.put(not p,width=>7);

put(" | ");b_io.put(p and q,width=>7);

put(" | ");b_io.put(p or q,width=>6);

put(" | ");b_io.put(p xor q,width=>7);

put(" |");

new_line;

end loop;

end loop;

end pr29;

Wróćmy jeszcze do przesłaniania przez licznik pętli wartości zmiennych lub stałych zadeklarowanych w programie, a mających tę samą nazwę. Czy to oznacza, że nie możemy w ogóle skorzystać z przesłoniętej zmiennej? Na szczęście nie. Musimy jedynie poprzedzic ją nazwą procedury, z której pochodzi, i kropką, jak w poniższym programie:


-- program demonstrujacy przeslanianie

-- zmiennych przez licznik petli


with ada.text_io;

use ada.text_io;


procedure pr30 is
package int_io is new ada.text_io.integer_io(integer);

use int_io;


i:integer:=8;
begin
put(i,0); -- wypisze 8

new_line;

for i in 1..3 loop

put(i,0); -- wypisze 1, 2 lub 3

new_line;

put(pr30.i,0); -- wypisze 8

new_line;

end loop;

end pr30;
Pętle możemy także w sobie zagnieżdżać (czyli umieszczać jedną pętlę w drugiej). Przykład tego widzieliśmy już w programie pr29. Jeżeli jednak przypadkiem nazwiemy liczniki obu pętli jednakowo, to licznik pętli wewnętrznej przesłoni licznik pętli zewnętrznej, na przykład
-- program demonstrujacy przeslanianie licznika petli

-- przez drugi licznik (petli zagniezdzonej)

-- o tej samej nazwie
with ada.text_io;

use ada.text_io;


procedure pr31 is
package b_io is new ada.text_io.enumeration_io(boolean);

use b_io;

package int_io is new ada.text_io.integer_io(integer);

use int_io;


begin

for i in 1..3 loop

for i in boolean loop

put(i); -- wypisze wartosc logiczna

new_line;

end loop;

put(i,0); -- wypisze liczbe

new_line;

end loop;

end pr31;


Jeżeli zaś chcemy w wewnętrznej pętli wypisać liczbę będącą wartością licznika pętli zewnętrznej, to musimy najpierw nadać nazwę pętli zewnętrznej (lub obu pętlom) przez napisanie
nazwa_pętli:

....... loop

........ end loop nazwa_pętli;
Od tej pory możemy odwoływać się do potrzebnej wartości pisząc
nazwa_pętli.nazwa_licznika_pętli
Przykład takiego nazywania pętli znajduje się w poniższym programie
-- program demonstrujacy nazywanie petli

-- oraz jego skutki


with ada.text_io;

use ada.text_io;


procedure pr32 is
package b_io is new ada.text_io.enumeration_io(boolean);

use b_io;

package int_io is new ada.text_io.integer_io(integer);

use int_io;


begin

petla_duza:

for i in 1..3 loop

for i in boolean loop

put(i,0); -- wypisze wartosc logiczna

new_line;

put(petla_duza.i,0); -- wypisze liczbe

new_line;

end loop;

put(i,0); -- wypisze liczbe

new_line;

end loop petla_duza;

end pr32;

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

1   ...   5   6   7   8   9   10   11   12   ...   16


©absta.pl 2016
wyślij wiadomość

    Strona główna