PP1 wyklad 2


Podstawy Programowania
Wykład drugi:
Inicjalizacja zmiennych, operatory.
1.Inicjalizacja zmiennych
Zanim użyjemy zmiennej w programie, powinniśmy nadać jej jakąś wartość po-
czątkową (zainicjalizować zmienną). Brak inicjalizacji jest jednym
z najczęstszych błędów, jakie popełniają programiści. Inicjalizację zmiennej
możemy wykonać na kilka sposobów. Domyślnie wszystkie zmienne globalne
(zadeklarowane w sekcji var programu głównego) mają zerową wartość począt-
kową (tzn. w przypadku zmiennej typu byte jest to 0, w przypadku real wartość
0.0, w przypadku char znak o kodzie ASCII równym 0). Jeśli chcemy, aby
zmienna miała wartość zerową wystarczy zadeklarować ją jako zmienną global-
ną. Jeśli chcemy nadać jej jakąś wartość różną od zera możemy postąpić na
dwa sposoby: użyć instrukcji przypisania (:=) lub zadeklarować ją jako zmienną
zainicjalizowaną. Oto przykład programu, który stosuje oba sposoby inicjaliza-
cji zmiennej.
Instrukcja przypisania powoduje
program inicjalizacja;
nadanie zmiennej znajdującej się po
const
jej lewej stronie wartości znajdującej
y:integer = -1;
się po jej prawej stronie. Ta wartość
var
może być stałą, wartością wyrażenia,
x:integer;
lub wartością innej zmiennej.
begin
Zmienną inicjalizowaną deklarujemy
x:=5;
w sekcji programu rozpoczynającej
writeln('Wartość x ',x);
się słowem kluczowym const (w tym
writeln('Wartość y ',y);
wypadku może ona również wy-
y:=-4;
stępować po części var). Deklaracja
writeln('Nowa wartość y ',y);
tej zmiennej jest podobna do dekla-
readln;
racji stałej, z tym, że podajemy typ.
end.
Uruchamiając program można prze-
konać się, że jest to rzeczywiście
zmienna, a nie stała. W czwartym od końca wierszu programu następuje
zmiana jej wartości, co w przypadku stałej nie jest możliwe. Zamiast inicjalizo-
wać zmienną bezpośrednio w programie, możemy poprosić użytkownika o po-
danie wartości, jaką chce nadać zmiennej. Najprościej zrobić to przy pomocy
procedury readln. Jeśli chcemy, aby użytkownik nadał zmiennej o nazwie
a jakąś wartość, w treści programu umieszczamy zapis: readln(a); Procedura
readln zatrzyma program do czasu, aż użytkownik wprowadzi odpowiednią war-
tość i naciśnie klawisz Enter. Po uzyskaniu w ten sposób wartości, procedura
przypisuje ją zmiennej a. Jeśli wywołamy tę procedurę bez żadnej zmiennej, to
spowoduje ona tylko zatrzymanie programu do czasu naciśnięcia przez użyt-
kownika wspomnianego wcześniej klawisza. Istnieje również możliwość  równo-
czesnego zainicjalizowania przez tę procedurę dwóch zmiennych np.: a i b. Wó-
2
wczas należy użyć tej procedury następująco: readln(a,b); Użytkownik
programu powinien podać dwie wartości rozdzielone spacją i nacisnąć Enter.
Zalecam jednak używanie procedury readln z pojedynczymi zmiennymi. Aby
wypisać wartość zmiennej na ekran możemy użyć procedury write lub writeln.
Druga różni się od pierwszej tym, że po wypisaniu komunikatu na ekran
umieszcza kursor w następnym wierszu ekranu. Jeśli chcemy wypisać na
ekran wartość zmiennej a możemy zrobić to następująco: writeln(a);. Jeśli chce-
my dodać komunikat, to umieszczamy go w apostrofach i po przecinku wy-
mieniamy nazwę zmiennej, której wartość chcemy wypisać: writeln('Wartość
zmiennej a to ',a);. W przypadku, kiedy wartość zmiennej jest liczbą całkowitą
lub naturalną, możemy określić również na ilu miejscach na ekranie ma zostać
wypisana, np.: writeln('Wartość zmiennej a to ',a:3); W tym przypadku zostaną
zarezerwowane trzy miejsca na ekranie na wypisanie wartości zmiennej. Dla
wartości zmiennoprzecinkowej możemy podać również, ile miejsc chcemy zare-
zerwować na część ułamkową: writeln('Wartość zmiennej a ',a:3:2); - w tym
przypadku zostaną zarezerwowane trzy miejsca na wypisanie wartości liczby,
w tym dwa na część ułamkową. Oto program pokazujący kilka sposobów
inicjalizacji zmiennych różnego typu:
program inicjalizacja_2;
uses
crt;
var
logiczna:boolean;
znak:char;
liczba_naturalna:byte;
liczba_calkowita:shortint;
liczba_rzeczywista, lrz:real;
lancuch:string;
begin
clrscr;
logiczna:=TRUE;
lrz:=3e-10; {Liczba e oznacza podstawę potęgi 10, czyli jest to trzy razy dziesięć do potęgi minus dziesiątej}
liczba_rzeczywista:=0.03;
znak:=#65; {65 to kod ASCII dużej litery A, poprzedzamy go znakiem #}
writeln('Wartość lrz bez formatowania ',lrz);
writeln('Wartość liczba_rzeczywista z formatowaniem :3:2 ', liczba_rzeczywista:3:2);
writeln('Znak: ',znak);
lancuch:='Napis';
3
writeln(lancuch);
liczba_naturalna:=4;
liczba_calkowita:=liczba_naturalna;
writeln(liczba_naturalna:4);
writeln(liczba_calkowita:10);
znak:='a'; {W ten sposób też możemy inicjalizować zmienną typu char  podając znak w apostrofach}
writeln(znak);
readln;
end.
Oprócz tych sposobów inicjalizacji zmiennych, które zostały uwzględnione
w programie możemy również nadać zmiennej wartość pseudolosową1. W tym
celu najpierw musimy wywołać procedurę randomize, poza wszelkimi instruk-
cjami iteracyjnymi2, a następnie dla uzyskania konkretnej wartości musimy
wywołać funkcję random z parametrem, będącym wartością mieszczącą się
w typie word, np.: a:=random(10); gdzie a jest zmienną typu całkowitego. Taki
zapis oznacza, że tej zmiennej zostanie przypisana pseudolosowa wartość
całkowita z przedziału od 0 do 9. Jeśli chcemy wylosować tylko wartość ułam-
kową, to musimy wywołać random, bez żadnego parametru, wówczas losowane
będą wartości z przedziału od [0,1). Jeśli inicjalizując zmienna pewną liczbą,
wygodniej będzie ją nam zapisać w kodzie szesnastkowym, to możemy to uczy-
nić poprzedzając jej wartość znakiem $, np.: x:=$5a; Jeśli zmiennej nadajemy
w programie (obojętnie w jaki sposób) kilkukrotnie wartość (a tak najczęściej
robimy), to tylko pierwsze przypisanie jest nazywane inicjalizacją.
2.Operatory i wyrażenia
Język Pascal oferuje szereg operatorów, które umożliwiają budowanie wyrażeń
i przeprowadzanie operacji na wartościach zmiennych. Poniższa tabela przed-
stawia najważniejsze z nich, wraz z ich priorytetami.
Operator Priorytet Kategoria
+,-,not 1 (najwyższy) jednoargumentowe
*,/,div,mod,and,shl,shr 2 multiplikatywne
+,-,or,xor 3 addytywne
=,<>,<,>,<=,>= 4 (najniższy) relacyjne
Priorytet określa kolejność wykonywania operatorów w wyrażeniu (kolejność
1 Ponieważ sposób generowania takich wartości nie gwarantuje ich  pełnej losowości, to nie
mówimy o nich, że są losowe, tylko pseudolosowe.
2 O tych instrukcjach dowiemy się na następnym wykładzie.
4
działań). Najwyższy mają operatory jednoargumentowe. Operator  powoduje
zmianę znaku liczby na przeciwny, + nie zmienia wartości liczby (został
wprowadzony jako dopełnienie poprzedniego operatora), natomiast operator not
jest operatorem negacji  zamienia wartość każdego bitu liczby na przeciwną
(0 na 1 i odwrotnie). Niższy priorytet mają operatory multiplikatywne: * oznacza
mnożenie, / dzielenie, div dzielenie całkowite (bez reszty), mod  operacja
modulo (reszta z dzielenia), and  operator mnożenia logicznego, shl  mnożenie
liczby przez potęgę dwójki (przesunięcie jej reprezentacji binarnej o zadaną licz-
bę miejsc w lewo), shr  dzielenie liczby przez potęgę dwójki (przesunięcie jej
reprezentacji binarnej o zadaną liczbę miejsc w prawo). Kolejne są operatory
addytywne. Operator + oznacza dodawanie lub, jeśli jego argumentami są
zmienne typu string lub char, łączenie zawartości tych zmiennych (konkate-
nację). Operator or oznacza sumę logiczną, operator xor różnicę symetryczną.
Najniższe priorytety mają operatory relacyjne: = to operator porównania (nie
mylić z instrukcją przypisania !!), <> operator  różne , < operator  mniejsze ,
>  operator większe , <= mniejsze lub równe, >= większe lub równe. Operatory
te zwracają wartość logiczną i mogą porównywać nie tylko zmienne liczbowe,
ale również zmienne typu string, char i boolean. Należy pamiętać, że operacje
arytmetyczne są wykonywane modulo zakres typu zmiennej.
Przykład:
program operatory_1;
uses
crt;
var
a:byte;
begin
clrscr;
a:=255;
a:=a+1;
writeln(a);
readln;
end.
W wyniku wykonania tego programu na ekranie zobaczymy nie liczbę 256, lecz
zero. Dlaczego ? - liczba 256 nie mieści się w zakresie typu byte i dlatego zosta-
nie  obcięta do wartości zero. Jeśli zamiast o jeden zwiększylibyśmy jej wartość
o 2, to otrzymalibyśmy w wyniku liczbę 1. Jeśli jednak umieścilibyśmy wyraże-
nie a+1 bezpośrednio w instrukcji writeln: writeln(a+1); to otrzymalibyśmy po-
prawny wynik. Dzieje się tak dlatego, że procedura write (lub writeln) zakłada
dla wyrażeń w których występują zmienne typu byte i word, że wynik jest typu
word. Oznacza to, że problemy wystąpią dopiero przy wartościach wyrażeń
5
większych niż 65535. Podobne zjawisko zachodzi również dla innych typów
zmiennych:
program operatory_2;
uses
crt;
var
x:shortint;
begin
clrscr;
x:=-128;
x:=x-1;
writeln(x);
readln;
end.
Wyjaśnienia wymaga sposób działania operatorów and, or, xor oraz shl i shr.
Działanie operatora and dotyczy wszystkich bitów jego argumentów. Jeśli bity
argumentów, znajdujące się na tej samej pozycji są równe jeden, to odpowiada-
jący im bit wyniku będzie miał wartość 1, w innych przypadkach wartość 0.
Np.: 5 and 3 da wartość 1, bo:
00000101
and 00000011
00000001
Jeśli argumentami tego operatora są wartości logiczne, to zwraca on wartość
TRUE, wtedy i tylko wtedy, kiedy oba argumenty też są równe TRUE.
Operator or również działa na poziomie bitów, ale według innej reguły. Bit znaj-
dujący się na określonej pozycji w wyniku ma wartość zero, wtedy i tylko wte-
dy, gdy oba odpowiadające mu bity argumentów mają też wartości zero.
W przeciwnym wypadku ma wartość 1. Np.: 5 or 3 daje wartość 7, bo:
00000101
or 00000011
00000111
Jeśli argumentami tego operatora są wartości logiczne, to zwraca on wartość
FALSE, wtedy i tylko wtedy, kiedy oba argumenty też są równe FALSE.
Operator xor ustawia wartość odpowiedniego bitu wyniku na wartość 1, wtedy
i tylko wtedy, gdy odpowiadające mu bity argumentów są różne, w przeciwnym
6
wypadku ten bit ma wartość 0. Np. 5 xor 3 daje wartość 6, bo:
00000101
xor 00000011
00000110
Jeśli argumentami tego operatora są wartości logiczne, to zwraca on wartość
TRUE, wtedy i tylko wtedy, kiedy wartości argumentów się różnią, a FALSE
kiedy są takie same.
Operator shr jest operatorem przesunięcia w prawo, czyli dzielenia całkowitego
przez potęgę dwójki. Wyrażenie 5 shr 2 daje wartość 1, bo
00000101 shr 2 = 00000001 (odpowiada wyrażeniu 5 div 4)
Jak można zaobserwować wartości najbardziej skrajnych bitów po prawej
stronie są tracone, natomiast bity po lewej stronie przyjmują wartość zero. Po-
dobnie działa operator shl, ale on dokonuje przesunięcia w lewo, czyli mnożenia
przez potęgę dwójki. Oto przykład 5 shl 2 = 20, bo
00000101 shl 2 = 00010100 (odpowiada wyrażeniu 5*4)
Język Trubo Pascal, pozwala również na budowanie wyrażeń logicznych,
w których używane są operatory relacyjne. Oto przykład programu, w którym
umieszczono dwa takie wyrażenia:
program operatory_3;
uses
crt;
var
a,b,c:boolean;
begin
clrscr;
a:=false;
b:=false;
c:=true;
writeln(a=b or c); {false}
writeln((a=b) or c); {true}
readln;
end.
7
3.Inne działania
Oprócz operatorów Pascal dostarcza programistom funkcji i procedur3, które
pozwalają na wykonanie innych operacji na zawartościach zmiennych. Do nich
między innymi należą:
succ - funkcja zwracająca następnik, działa tylko dla typów porządkowych, np.:
b := succ(a);
pred - funkcja zwracająca poprzednik, działa tylko dla typów porządkowych,
np.: b := pred(a);
ord - funkcja zamienia wartość typu porządkowego na wartość całkowitą, naj-
częściej służy do uzyskiwania kodu ASCII znaku, np.: x:=ord('a');
chr - funkcja zmienia wartość całkowitą na znak writeln(chr(97));
abs - funkcja zwraca wartość bezwzględną liczby writeln(abs(-5));,
int - funkcja, zwraca część całkowitą liczby zmiennoprzecinkowej, wartość
zwracana jest typu real;
frac - jak wyżej, ale zwraca część ułamkową,
trunc - podobnie jak int zwraca część całkowitą liczby rzeczywistej, ale jako
wartość typu integer,
high - funkcja ta zwraca maksymalną wartość, jaką da się zapisać w zmiennej
danego typu porządkowego,
low - jak wyżej, ale zwraca wartość minimalną,
3 Te pojęcia będą oczywiście wyjaśnione na innych wykładach, ale żeby zrozumieć zawartość tego
rozdziału wprowadzmy kilka nieformalnych definicji. Wywołanie procedury ma postać:
NazwaProcedury(parametry); parametrami mogą być zarówno wartości, jak i zmienne, z tym że
nie zawsze możliwa jest dowolność, tzn. w niektórych przypadkach parametry są parametrami
wyjściowymi i muszą być zmiennymi.
Wywołanie funkcji ma zaś postać:
Zmienna := NazwaFunkcji(parametry);
Funkcja zwraca zawsze jakąś wartość, która jest przypisywana zmiennej, lub ignorowana (wó-
wczas nie występuje instrukcja przypisania i jej lewa strona). Zarówno w przypadku procedur,
jak i funkcji nie zawsze musi występować lista parametrów, niektóre z nich po prostu nie wy-
magają żadnych parametrów.
8
round - funkcja wykonuje zaokrąglenie części ułamkowej liczby
zmiennoprzecinkowej, wartość wynikowa jest typu longint,
str  procedura ta zamienia wartość liczbową na łańcuch znaków, np.:
str(11.58:4:2, nap); gdzie nap jest zmienną typu string,
val  dokonuje konwersji w drugą stronę, tzn. zamienia łańcuch znaków na
liczbę, np.: val('25.5',liczba,blad), gdzie liczba jest zmienną typu real (może być
też zmienną typu integer), blad zmienną typu integer. W razie niepowodzenia
konwersji w zmiennej blad będzie zapisany numer pozycji znaku, który
spowodował błąd.
sin  funkcja zwracająca wartość sinusa dla określonej wartości kąta, parametr
i wartość zwracana są typu real. Przyjmuje, że kąt jest wyrażony w radianach!
cos  jak wyżej, ale zwracana wartość cosinusa.
exp  funkcja zwracająca wartość funkcji ex (eksponenty).
ln  funkcja zwracająca wartość logarytmu naturalnego4.
sizeof  funkcja, która podaje rozmiar zmiennej (liczbę bajtów którą zajmuje
w pamięci).
sqr  funkcja zwracająca kwadrat wartości podanej jej przez parametr.
sqrt  funkcja zwracająca pierwiastek kwadratowy wartości podanej jej przez
parametr.
odd  funkcja zwraca wartość TRUE, jeśli podana jej liczba całkowita, miesz-
cząca się w zakresie typu longint jest wartością nieparzystą.
inc  procedura zwiększająca wartość zmiennej podanej jej jako pierwszy para-
metr, o wartość, która jest jej podana jako drugi parametr. Jeśli drugi parametr
nie występuje, to wartość zmiennej jest zwiększana o jeden.
dec  jak wyżej, ale wartość zmiennej jest zmniejszana,
hi  podaje wartość starszego bajta zmiennych typu word i integer (2 baj-
4 Jeśli chcemy obliczyć wartość funkcji ax, gdzie a i x są liczbami zmiennoprzecinkowymi i a>0, to
możemy skorzystać z wyrażenia exp(x*ln(a))
9
towych).
lo  jak wyżej, ale podaje wartość młodszego bajta.
swap  zamienia miejscami wartości bajtów zmiennych typu word i integer.
W przypadku kompilatora FreePascal funkcje lo i hi oraz procedura swap mogą
działać dla typów danych, które są 32-bitowe (mają wielkość 4 bajtów). W takich
przypadkach zamieniane są miejscami słowa (2-bajty), tzn. starsze słowo jest
zamieniane z młodszym słowem.
4.Zgodność i konwersje typów zmiennych
Załóżmy, że mamy dane dwie zmienne. Pierwsza nazywa się x i jest typu T1,
a druga y i jest typu T2. Przypisanie x:=y; jest poprawne jeśli spełniony jest
któryś z warunków:
typy T1 i T2 są identyczne,
typ T1 i T2 są zgodnymi typami porządkowymi, a wartość zmiennej y jest
jedną z możliwych wartości w typie T1,
typy T1 i T2 są typami zmiennoprzecinkowymi i wartość zmiennej y po
zaokrągleniu jest jedną z możliwych wartości w typie T1,
typ T1 jest typem zmiennoprzecinkowym, a typ T2 jest typem całkowitym,
T1 i T2 są typami całkowitymi,
T1 jest typem łańcuchowym (string), a T2 jest typem znakowym.
W innych przypadkach musimy zastosować konwersję typów wartości. Dla
zmiennych porządkowych możliwa jest konwersja według schematu: x :=
NazwaTypu(y); przykładowo x:=Integer('A'); Inne konwersje wykonujemy korzy-
stając, z funkcji i procedur, które zostały opisane w poprzednim rozdziale. Jeśli
nie dokonamy takiej konwersji, to kompilator zgłosi błąd.
10


Wyszukiwarka