home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1997 #3
/
amigamamagazinepolishissue03-1
/
ma_1995
/
04
/
ami036.txt
< prev
next >
Wrap
Text File
|
1997-04-06
|
14KB
|
423 lines
/* wyraûenia zawarte w >...< proszë pogrubiê */
AMIGA E 8^)
<lead>Witajcie kursanty! Jak to czas leci! Juû od póî roku i dwóch
miesiëcy tîuczemy sië z Amiga E... Jest kwiecieï, warto wyjôê na
powietrze, pojeúdziê na rowierze, oderwaê sië od komputerów...
Jeûeli jednak tego nie moûesz zrobiê, polecam pîytkë Sheryl Crow
o tytule "Tuesday Night Music Club". Album jest bardzo dobry,
znalazîem na nim co najmniej trzy utwory o poziomie
przewyûszajâcym zjechany do biaîoôci hit "All I Wanna Do". Poza
tym panienka jest nie tylko îadna, ale teû umie ôpiewaê...
<a>Rafaî Wiosna
<txt> Tak BTW*1: Naukowcy z Uniwersytetu Warszawskiego twierdzâ,
ûe koderzy, którzy w przerwach w czasie programowania grajâ w grë
Deluxe Galaga 2.5, sâ o 37% bardziej efektywni i robiâ o 17,3%
mniej bîëdów. Zadziwiajâce, nieprawdaû?... 8^)
<sr>Ciâgi
<txt> Dziô zajmë sië gîëbiej typem danych, zwanych ciâgiem lub, z
angielskiego, stringiem. Jest to jedna z najprostszych postaci
tablicy, typu danych, którego omówienie zostawimy sobie na
przyszîoôê. >Ciâg< w Amiga E to zestaw nastëpujâcych po sobie w
pamiëci bajtów, bëdâcych najczëôciej normalnym napisem w kodzie
ASCII, zakoïczony bajtem o wartoôci 0 ('\0'). Zmienna
reprezentujâca ciâg ma wartoôê odpowiadajâcâ jego poîoûeniu
(adresowi) w pamiëci.
Spójrz na poniûszy program:
<l>PROC main()
DEF s:PTR TO CHAR, i
s:='To jest ciâg znaków'
FOR i:=0 TO 19
WriteF('$\h : \z\d[3] "\c"\n',s+i,s[i],s[i])
ENDFOR
WriteF('\n')
ENDPROC
<txt>W drugiej linii definiowana jest zmienna s jako wskaúnik do
znaku. W nastëpnej jest jej nadawana wartoôê, bëdâca adresem
ciâgu znaków, zawartego miëdzy apostrofami. Teraz, korzystajâz z
pëtli FOR...ENDFOR, poznanej miesiâc temu, moûesz wypisaê
nastëpujâce wartoôci: adres w zapisie heksadecymalnym, wartoôê
bajtu wskazywanego przez ten adres oraz znak kodu ASCII, który
reprezentuje të wartoôê. Zainteresowanym mogë powiedzieê, ûe
zapis s[i] oznacza indeks tablicy (tutaj, i jest mnoûone przez 1,
czyli dîugoôê jednego jej elementu; gdybyômy zadeklarowali s jako
PTR TO WORD, kaûde i zostaîoby przemnoûone przez dwa -- czyli
dîugoôê typu WORD).
Amiga E wprowadza specjalny typ zmiennej: >E-ciâg< (E-string). Od
normalnego ciâgu róûni sië wîaôciwie tylko nazwâ, gdyû E-ciâg
moûe zastâpiê ciâg wszëdzie, gdzie zaûyczy sobie tego programista
(w skîadni wywoîaï funkcji, które póúniej bëdâ zamieszczone,
napis "ciâg" moûna dowolnie zamieniaê na "E-ciâg"). Nie moûna
tego zrobiê odwrotnie -- w konstrukcjach, które wymagâjâ E-ciâgu,
uûycie normalnego ciâgu jest niemoûliwe. Najwaûniejszâ róûnicâ
jest fakt, ûe na E-ciâgu moûna wykonywaê dowolne operacje
zmieniajâce jego dîugoôê, a na zwykîym ciâgu -- nie. E-ciâg wie,
jakie sâ jego granice, a dokîadniej, pamiëta o tym generowany
przez kompilator kod.
E-ciâg definiowany jest jako typ STRING w nastëpujâcy sposób:
<l>PROC main()
DEF s[20]:STRING, i
StrCopy(s,'To jest ciâg znaków',ALL)
FOR i:=0 TO 19
WriteF('\h : \z\d[3] "\c"\n',s+i,s[i],s[i])
ENDFOR
WriteF('\n')
ENDPROC
<txt>Jak widzisz, definicja E-ciâgu wymusza na programiôcie
okreôlenie jego maksymalnej dîugoôci. Spróbuj zmieniê liczbë 20
na 10 i zobacz, co sië stanie...
Niektórzy AMOS-owcy mogâ zapytaê "co to za funkcja StrCopy() i
dlaczego nie napisaîeô po prostu s:='To jest ciâg znaków'?" Jest
to charakterystyczne pytanie dla programistów, majâcych stycznoôê
z BASIC-em. Takie przyzwyczajenia mogâ prowadziê do powaûnych
kîopotów z sercem oraz podwyûszonego poziomu agresji u
programisty 8^). Otóû dlatego, ûe nie moûna PRZYPISYWAÊ CIÂGÓW do
zmiennych zdefiniowanych jako E-ciâg. Zauwaû, ûe gdybym tak
zrobiî, zmienna s wskazywaîaby wprawdzie na ciâg (a nie na
E-ciâg), ale na tym by sië skoïczyîo -- ûadna operacja na
zmiennej s, traktowanej jako wskaúnik do E-ciâgu, nie byîaby
wykonalna, tzn. mogîaby prowadziê do zawieszenia sië komputera
(ciâg nie ma jednej okreôlonej dîugoôci, której nie moûna
zmieniaê; gdyby dodaê do niego drugi ciâg, okazaîoby sië, ûe po
tej operacji zamazaîby kod znajdujâcy sië w pamiëci zaraz po
nim). Funkcjë StrCopy() omówië juû zaraz.
Moûe juû zauwaûyîeô, ûe nastëpnâ róûnicâ miëdzy E-ciâgiem a
normalnym ciâgiem jest fakt, ûe przy definicji E-ciâgu zmienna
automatycznie przybiera odpowiedniâ wartoôê, czyli wskazuje na
tenûe E-ciâg. Przy definicji ciâgu zmienna, aû do chwili
przypisania jej tegoû ciâgu, ma wartoôê nieokreôlonâ. Z tym wiâûe
sië teû to, ûe nowo zdefiniowany E-giâg jest pusty, natomiast
nowo zdefiniowany ciâg jest NIEOKREÔLONY. Chcesz sprawdziê?
Zmieï drugâ linië ostatniego programu na:
<l>DEF s:PTR TO CHAR, i
<txt>Twoje szczëôcie, ûe kompilator E nie ustawi tej zmiennej na
0, a gdzieô na obszar stosu, przeznaczonego dla tego programu,
gdyû trzecia linia spowodowaîaby przepiëknâ wizytë naszego
ulubionego Guru... (dla ambitnych: wyjaônijcie sobie dlaczego).
Amiga E ma kilka zdefiniowanych funkcji, przeznaczonych do
manipulacji na E-ciâgach. Pierwszâ z nich jest funkcja
>String(MAXSIZE)<. Rezerwuje ona pamiëê na E-ciâg o dîugoôci
MAXSIZE. Wartoôciâ funkcji jest adres kawaîka pamiëci. Jest
interesujâce, ûe korzystajâc z tej funkcji, moûna zmieniê
nieokreôlonâ zmiennâ typu PTR TO CHAR (ciâg) na zainicjowanâ
zmiennâ typu STRING (E-ciâg). Gdyby dodaê linië:
<l>s:=String(20)
<txt>do ostatniej wersji naszego przykîadowego programu (tej z
DEF s:PTR TO CHAR _ORAZ_ StrCopy()), wpisujâc jâ miëdzy linie 2 i
3, okaûe sië, ûe zmienna s jest teraz wskaúnikiem do pustego
E-ciâgu. Ûeby nie byîo nieporozumieï, zapis:
<l>DEF s[20]:STRING
<txt>moûna zastâpiê dwoma liniami:
<l>DEF s:PTR TO CHAR
s:=String(20)
<txt>Funkcja ta umoûliwia dynamicznâ alokacjë E-ciâgów, których
dîugoôci jeszcze nie znamy.
Waûne jest to, ûeby sprawdziê, czy przypadkiem wynikiem funkcji
nie bëdzie staîa NIL, która w Amiga E ma wartoôê 0. Jeûeli tak
sië stanie, oznacza to fakt braku pamiëci na E-ciâg. Jeûeli to
zignorujesz, moûesz sië spodziewaê szybkiego zawieszenia sië
programu w sytuacji, gdy zabraknie miejsca. Moûna tego bardzo
îatwo uniknâê, dodajâc linië:
<l>RAISE BLAD_BRAKPAMIECI IF String()=NIL
<txt>na poczâtku programu. (Pamiëtaj, ûeby zdefiniowaê ten numer
bîëdu w poczâtkowych ENUM-ach oraz odpowiednio na niego reagowaê
w handlerze bîëdów). Czyû obsîuga sytuacji podbramkowych w Amiga
E nie jest piëkna? Moûe nie, ale na pewno pozwala programiôcie
skoncentrowaê sië na treôci, a nie na formie...
Funkcjë StrCopy() juû raz zastosowaîem. Ma ona nastëpujâcâ
skîadnië >StrCopy(E-ciâg,ciâg,dîugoôê=ALL)<. Jej zadaniem jest
skopiowanie ciâgu (lub E-ciâgu) do E-ciâgu. Funkcja zwraca
wskaúnik do wyniku. Spójrz na przykîady jej uûycia:
<l>DEF s[20]:STRING
StrCopy(s,'To jest ciâg znaków',ALL)
StrCopy(s,'A to jest ciâg dluûszy niû 20 znaków',ALL)
StrCopy(s,'1234567890',7)
StrCopy(s,'',ALL)
<txt>Pierwszy przykîad skopiuje znaki z ciâgu, bëdâcego drugim
parametrem funkcji, do E-ciâgu, bëdâcego jej pierwszym
parametrem. Skopiowane zostanâ wszystkie znaki ciâgu, a to dziëki
temu, ûe ostatni parametr ma umownâ wartoôê ALL.
W drugim przykîadzie, do E-ciâgu s zostanie skopiowanych tylko 20
pierwszych znaków ciâgu "A to jest...". Dlaczego? Dlatego, ûe
kompilator pamiëta o definicji E-ciâgu s, którego dîugoôê nie
moûe przekraczaê 20 bajtów.
Trzeci przykîad skopiuje tylko 7 znaków z ciâgu, zawierajâcego
cyferki. Jeûeli przykîady 2. i 3. zostanâ wykonane w programie
po sobie, E-ciâg s po tym bëdzie miaî dîugoôê 7 znaków, a nie 20.
StrCopy() kopiuje ciâgi, a nie wkleja ich!
Ostatni przykîad kopiuje ciâg pusty. W wyniku tego E-ciâg s
bëdzie miaî dîugoôê 0.
Umowna dyrektywa ALL nie jest konieczna w Amiga E 3.x, które
wprowadziîo parametry domyôlne. Dziëki temu jeûeli w funkcji
StrCopy() sâ tylko dwa parametry, kompilator rozszerza jâ o
trzeci, domyôlny, którego wartoôciâ jest ALL. Zaoszczëdza to
pisania:
<l>StrCopy(s,'ciâg',ALL)
to to samo w Amiga E 3.x co
StrCopy(s,'ciâg')
<txt>Modyfikacjâ StrCpy() jest funkcja
>RightStr(E-ciâg1,E-ciâg2,dîugoôê), która kopiuje znaki z koïca
drugiego E-ciâgu do pierwszego. Przykîad:
<l>DEF s[20]:STRING, t[20]:STRING
StrCopy(t,'1234567890')
RightStr(s,t,1)
WriteF('"\s"\n',s) -> "0"
RightStr(s,t,7)
WriteF('"\s"\n',s) -> "4567890"
<txt>Komentarze pokazujâ postaê E-ciâgu s po wykonaniu funkcji
RightStr(). Nie moûna w niej uûyê dyrektywy ALL zamiast
konkretnego okreôlenia dîugoôci kopiowanych znaków. Byîoby to bez
sensu i stanowiîoby powielenie funkcji StrCopy().
Jeûeli juû mówimy o dîugoôci ciâgów, warto poznaê funkcjë
pozwalajâcâ na jej zmierzenie(?). >StrLen(ciâg)< w wyniku zwraca
dîugoôê ciâgu (lub E-ciâgu). W wypadku E-ciâgów lepiej uûyê
funkcji >EstrLen(E-ciâg)<, która nie bëdzie poszukiwaîa bajtu o
wartoôci 0 w podanym ciâgu, a zwróci jego dîugoôê natychmiast.
Jest to nastëpna zaleta E-ciâgów.
Podobnâ funkcjâ jest >StrMax(E-ciâg)<, która to zwraca maksymalnâ
dîugoôê E-ciâgu bëdâcego parametrem. W wiëkszoôci wypadków, jak
moûna sië tego spodziewaê, prawdziwa dîugoôê nie bëdzie równa
maksymalnej.
Bardzo przydatnâ funkcjâ jest >StrCmp(ciâg,ciâg,dîugoôê=ALL)<.
Porównuje ona dwa (E-)ciâgi i zwraca wartoôê TRUE, jeûeli sâ one
jednakowe, lub FALSE, jeûeli sâ róûne. Po co taka funkcja? Czy
nie proôciej napisaê IF s=e THEN... Otóû znowu tak moûna
zorganizowaê porównywanie ciâgów w BASIC-u, a nie w Amiga E. Tak
sformuîowana instrukcja warunkowa porówna ADRESY (E-)ciâgów, a
nie ich ZAWARTOÔC!
Najlepiej dziaîanie funkcji zobrazujâ przykîady. Wszystkie poniûsze
wywoîania StrCmp() dajâ w wyniku wartoôê TRUE:
<l>StrCmp('ABC', 'ABC')
StrCmp('ABC', 'ABC', ALL)
StrCmp('ABCd', 'ABC', 3)
StrCmp('ABCde','ABCxxjs',3)
<txt>A teraz przykîady przy których StrCmp() zwraca FALSE:
<l>StrCmp('ABC', 'ABc')
StrCmp('ABC', 'ABc', ALL)
StrCmp('ABCd', 'ABC', ALL)
<txt>Kolejnâ funkcjâ jest >StrAdd(E-ciâg,ciâg,dîugoôê=ALL), która
dodaje (E-)ciâg do E-ciâgu:
<l>DEF s[20]:STRING
StrCopy(s,'12345')
StrAdd(s,'67890',ALL)
WriteF('"\s"\n',s) -> "1234567890"
StrAdd(s,'ABDEF',3)
WriteF('"\s"\n',s) -> "1234567890ABD"
<txt>Bardziej zaawansowanâ funkcjâ operujâcâ na (E-)ciâgach jest
>MidStr(E-ciâg,ciâg,pozycja,dîugoôê=ALL). Ma ona za zadanie
skopiowanie znaków z (E-)ciâgu, bëdâcego drugim parametrem, do
pierwszego parametru -- E-ciâgu. Skopiowane zostanie tyle znaków,
ile okreôlimy w czwartym parametrze. Z (E-)ciâgu bedâcego drugim
parametrem bëdâ one kopiowane od pozycji okreôlonej parametrem
trzecim. Najlepiej pokaûâ to przykîady:
<l>DEF s[20]:STRING
MidStr(s,'1234567890',2,ALL)
WriteF('"\s"\n',s) -> "34567890"
MidStr(s,'1234567890',6,3)
WriteF('"\s"\n',s) -> "789"
<txt>Jak widaê, pozycje w ciâgu liczy sië od zera.
Bardzo przydatnâ funkcjâ jest >InStr(ciâg1,ciâg2,pozycja=0)<.
Przeszukuje ona (E-)ciâg1 pierwszy i sprawdza, czy nie wystâpiî
(E-)ciâg2. Poszukiwania moûna zaczâê od okreôlonej trzecim
parametrem pozycji (E-)ciâgu1 (jeûeli tego parametru brak,
szukanie zacznie sië od samego poczâtku). InStr() zwraca pozycjë,
na której zostaî znaleziony (E-)ciâg2 (UWAGA! moûe to byê 0!) lub
-1, jeûeli go nie znaleziono. Jak moûna sië domyôliê, przy
poszukiwaniu rozróûniane sâ litery duûe i maîe (case sensitive).
A propos wielkoôci liter, to dwie funkcje, >LowerStr(ciâg)< i
>UpperStr(ciâg)< zamieniâ twój (E-)ciâg odpowiednio na maîe i
duûe literki.
Równieû przydatnâ funkcjâ jest >TrimStr(ciâg)<. Zwraca ona adres
pierwszego "drukowalnego" znaku w (E-)ciâgu bëdâcym jej
parametrem. Przeskakiwane sâ spacje i znaki poniûej tej funkcji w
tabeli ASCII (czyli poniûej 32). Oto przykîad:
<l>DEF s[20]:STRING
StrCopy(s,' \n \t HEJ',ALL)
WriteF('"\s"\n',s) -> "{cr} HEJ"
WriteF('"\s"\n',TrimStr(s)) -> "HEJ"
<txt>W miejscu oznaczonym {cr} kursor przesunie sië na poczâtek
nastëpnej linii.
Mniej wykorzystywanâ funkcjâ jest >SetStr(E-giâg,dîugoôê)<.
Zmienia ona dîugoôê E-ciâgu na okreôlonâ drugim parametrem. Oto
przykîad uûycia:
<l>DEF s[10]:STRING
StrCopy(s,'1234567890')
WriteF('"\s"\n',s) -> "1234567890"
SetStr(s,5)
WriteF('"\s"\n',s) -> "12345"
SetStr(s,15)
WriteF('"\s"\n',s) -> "12345"
StrCopy(s,'12345678901234567890')
WriteF('"\s"\n',s) -> "1234567890"
<txt>Ostatniâ omówionâ przeze mnie funkcjâ, zwiâzanâ z
(E-)ciâgami jest >Val(ciâg,adres=NIL)<. Ma ona za zadanie zamianë
ciâgu znaków, w którym znajduje sië liczba na wartoôê typu LONG.
Val() zignoruje wszystkie spacje na poczâtku, a znaki "%" i "$"
przed liczbami zinterpretuje jako poczâtek zapisu dwójkowego lub
heksadecymalnego. Funkcja zwraca wartoôê odczytanâ z (E-)ciâgu.
Jeûeli drugi argument jest podany, to zmiennej WSKAZYWANEJ przez
niego zostanie wpisana liczba znaków, które funkcja Val() musiaîa
przejrzeê, aby obliczyê zwróconâ wartoôê.
Na pierwszy rzut oka wyglâda to na bardzo skomplikowane, ale w
"praniu" okazuje sië, ûe nie taki diabeî straszny. Przeôledúmy
przykîadowy kawaîek programu:
<l>DEF s[30]:STRING, value, chars, p:PTR TO CHAR
StrCopy(s,' \t \n 10 \t $3F -%0101010')
value:=Val('abcde 10 20',{chars}) -> ADRES zmiennej chars!
<txt>Po wykonaniu powyûszej linii zmienna "value", jak równieû
zmienna chars, bëdzie miaîa wartoôê 0. Dlaczego? Poniewaû 'abcde'
to nie jest liczba dla Val(). (Byîaby, gdyby dodaê na poczâtku
"$"!).
<l>value:=Val(s, {chars})
<txt>Teraz "value" ma wartoôê 10, a chars -- 7 (liczba znaków
przejrzanych przez funkcjë Val()).
<l>p:=s+chars
<txt>Teraz ciâg p wskazuje na siódmy znak E-ciâgu s.
<l>value:=Val(p,{chars})
<txt>Po tym "value" przybierze wartoôê 63 (czyli $3F), a zmienna
chars -- 6 (przejrzano nastëpne 6 znaków).
<l>p:=p+chars
<txt>Teraz ciâg p wskazuje na spacjë zaraz po "$3F" w E-ciâgu s.
<l>value:=Val(p,{chars})
<txt>Teraz "value" ma wartoôê -42 (-%0101010), a chars -- 10.
Powyûszy przykîad bardzo îadnie ilustruje, gdzie naleûy uûyê
ciâgu, a gdzie E-ciâgu.
<sr>*
Oops, to by byîo na tyle z (E-)ciâgami. Sâ jeszcze dwie funkcje z nimi
zwiâzane (ReadStr() i StringF()), ale zajmë sië nimi dopiero przy omawianiu
operacji wejôcia/wyjôcia. Na dziô to juû koniec. Przepraszam, ûe nie ma
comiesiëcznego listingu do wklepania, ale ta czëôê kursu E tak sië
rozrosîa, ûe nie ma na niego juû miejsca... BYE4NOW!
<przyp>*1 BTW -- By The Way, odpowiednik polskiego "swojâ drogâ".
Literatura: Jason R. Hulance, plik "Beginners.guide" rozprowadzany z Amiga
E 3.x.