Zadania do wykładu o konstrukcjach sterujących

Uniwersytet Gdański - Instytut Matematyki - Zakład Informatyki - Strona domowa

Perl: programowanie - Zadania do wykładu o konstrukcjach sterujących

Konstrukcje sterujące to ogólnie przyjęte twory programistyczne służące do zarządzania wykonaniem innych instrukcji. Należą do tej grupy m.in. instrukcje pętli (while, until, for, foreach) oraz instrukcje warunkowe (if oraz unless). Spróbuj "pobawić" się trochę tymi instrukcjami, ich zrozumienie jest kluczowe do wydajnego programowania.

  1. Wykorzystując pętlę while i zmienną $i, wypisz liczby od 1 do 10.
    Zadanie to było tak trywialne, że aż śmieszne. Mimo to zapewne znalazłbym osoby, które go nie zrobiły... Naturalna implementacja może wyglądać tak: perl -le '$i=1; while( $i <= 10 ){ print $i; $i++ }' Okazuje się, że w tym przypadku można (wyjątkowo) opuścić ustawianie zmiennej $i na wartość 1, dlatego, że pierwsza wartość użyta w pętli to undef, a print zamienia ją na napis pusty podczas wypisywania. Zatem w wersji: perl -le 'while( $i <= 10 ){ print $i; $i++ }' pojawi się dodatkowo na początku jedna pusta linia. Ale liczby zostaną wypisane od 1 do 10, przynajmniej takie się pojawią.
  2. Korzystając z pętli until zrób taki program, który wypisze liczby od 1 do 10. Zaobserwuj różnice w stosunku do wersji z while.
    Tutaj implementacja jest bardzo podobna, przestawieniu ulega jedynie ciało pętli i warunek jej zakonczenia jest inny: perl -le 'do{ print $i; $i++ } until $i > 10;' Podobnie jak w przypadku pętli while, pojawi się jedna pusta linia na skutek wypisania wartości undef (przy pierwszym użyciu zmiennej)
  3. Trywialne jest napisanie pętli for, która posłuży do wypisania za pomocą print liczb od 1 do 10. Ale czy potrafisz wygenerować w tej pętli liczby nieparzyste, parzyste, lub tworzące ciąg np. 1 3 7 15 31 63? Albo tworzące ciąg losowy liczb niemalejących? Jednym słowem, czy jesteś już Master of Loops?
    Ciąg liczb można otrzymać np. tak: for($i=0;$i<100;$i+=$i++){ print "$i "; } Ciąg liczb niemalejących losowych jeszcze prościej - wystarczy do poprzedniej wartości $i dodawać za każdym razem jakąś liczbę losową (ze stałego zakresu, np. int(10*rand) lub z rosnącego zakresu (int($i*rand): for($i=1;$i<100;$i+=int rand(10)){ print "$i "; } Poniższy kod działa na liczbach rzeczywistych, co dla pętli for w perlu nie stanowi problemu. for($i=1;$i<100;$i+=rand($i)){ print "$i "; }
  4. Przetestuj działanie polecenia next. W tym celu napisz pętlę, która generuje liczby od 1 do 10, ale wpisz tylko liczby parzyste. Użyj instrukcji warunkowej oraz next, aby pominąć liczby nieparzyste.
    Pętla powinna iterować po wszystkich liczbach od 1 do 10, ale wewnątrz pętli należy umieścić polecenie next, które spowoduje natychmiastowe przejście do nastepnej iteracji jeżeli liczba jest nieparzysta. Parzystość liczby sprawdzimy za pomocą operatora %, który zwraca resztę z dzielenia. Wiemy, że liczba nieparzysta dzielona przez 2 zawsze będzie miała resztę z dzielenia równą 1, czyli warunek $i % 2 będzie prawdziwy tylko dla liczb nieparzystych. I dla takich liczb wykonamy next, a pozostałe liczby wypiszemy: for($i=1;$i<10;$i++){ next if $i % 2; print "$i\n"; }
  5. Napisz prosty program - grę, która losuje liczbę z zakresu 1-1000 i cyklicznie pyta użytkownika o jej odgadnięcie. Program powinien po każdej odpowiedzi użytkownika podawać informację, czy podana liczba jest za mała, czy za duża. W przypadku trafienia, program (i pętlę, w której odbywa się dialog z użytkownikiem) należy przerwać poleceniem last.
    Zadanie to realizuje na przykład taki program, jak ten przedstawiony poniżej. Wykorzystano tutaj pętlę while dlatego, że nie wiemy, ile razy wykona się kod wewnątrz pętli, ponieważ nie wiemy, za którym razem gracz zgadnie liczbę: #!/usr/bin/perl -w use strict; my $tajemnica = int rand(1000)+1; while(chomp(my $liczba = )){ if( $liczba == $tajemnica){ print "dokladnie"; last; } if( $liczba < $tajemnica ){ print "za malo."; next; } if( $liczba > $tajemnica ){ print "za duzo."; next; } }
  6. Uwaga: to zadanie jest sformułowane błędnie (pomyłka z działaniem last - moja wina). Można go nie wykonywać! Gdy prowadzisz interakcję z użytkownikiem w pętli, być może jedna z jego odpowiedzi skłoni program do przerwania pętli za pomocą last (np. gdy wybierze polecenie zakończenia programu, jeżeli będzie taka możliwość). Wtedy możesz w bloku continue zaprogramować pytanie, "czy na pewno?" i w razie negatywnej odpowiedzi kontunuować przerwaną pętlę za pomocą redo. Napisz prosty program demonstrujący tę technikę (możesz wymyśleć jakąś prostą grę lub mały, interaktywny program usługowy).
  7. W perlu działa polecenie goto ETYKIETA. Samą etykietę można postawić przed blokiem kodu, np. LABEL:{ ... }. Gdy wewnątrz takiego "nazwanego" bloku użyjesz polecenia goto LABEL;, sterowanie programu zostanie przekazane do miejsca, gdzie zaczyna się blok. W ten sposób powstaje pętla, ponieważ program zaczyna wykonywać instrukcje cyklicznie. Korzystając z polecenia goto, napisz symulator działania pętli for, while oraz until. Oczywiście do sprawdzania warunku zakończenia pętli należy wykorzystać instrukcję warunkową. Zaprojektowane pętle wykorzystaj do wypisania liczb całkowitych od 100 do 110.
    Wykorzystanie etykiety do stworzenia pętli może zostać zapisane w sposób następujący: LOOP:{ # ... jakies polecenia programu goto LOOP; } Tego typu pętla to oczywiście pętla nieskończona ponieważ nie ma żadnego warunku zakończenia jej. Jedynie polecenia takie jak last mogą przerwać działanie pętli gdyż ominą instrukcję goto, wykonując skok do pierwszej instrukcji poza pętlą. Implementacja while różni się od until właściwie tylko położeniem instrukcji warunkowej określającej kiedy pętla się zakończy. Oto przykładowe implementacje: $i = 100; WHILE: if( $i < 111 ){ print "$i "; $i++; CONTINUE:{ # ten pusty blok tutaj istnieje po to, aby przypominac o obecnosci bloku continue w perlowym while } goto WHILE; } $i = 100; UNTIL: { print "$i "; $i++; CONTINUE:{ # ten pusty blok tutaj istnieje po to, aby przypominac o obecnosci bloku continue w perlowym unless } unless( $i > 110 ){ goto UNTIL; } } Na uwagę zasługuje tu fakt, że obie te pętle wymagają inicjalizacji zmiennej indeksującej ($i) przed rozpoczęciem, w zewnętrznej względem pętli instrukcji. Pętla for może wyglądać na przykład tak: FOR:{ $i = 100; LOOP:{ CONTINUE{ } if( $i < 111 ){ print "$i "; $i++; goto LOOP; } } }
Uniwersytet Gdański - Instytut Matematyki - Zakład Informatyki - Strona domowa - Perl - Zadania
[c] Piotr Arłukowicz, materiały z tej strony udostępnione są na licencji GNU.