Programmeerimise algkursus 91 - 91
Mida selle kursusel õpetatakse? 3
SISSEJUHATAV SÕNAVÕTT EHK 'MILLEKS ON VAJA PROGRAMMEERIMIST?' 3
PROGRAMMEERIMISE KOHT MUUDE MAAILMA ASJADE SEAS 4
PROGRAMMEERIMISKEELTE ÜLDINE JAOTUS 7
ESIMESE TEEMA KOKKUVÕTE 8
ÜLESANDED 9
PÕHIMÕISTED. OMISTAMISLAUSE. 9
9
SISSEJUHATUS 9
PROGRAMMEERIMISE MÕISTED 10
ARVUTIGA SEOTUD MÕISTED 14
OMISTAMISLAUSE 16
ÜLESANDED 19
ARITMEETILINE JA LOOGILINE
AVALDIS . OPERAND JA
OPERAATOR . 20
20
SISSEJUHATUS 20
20
AVALDIS 20
ÜLEVAADE ARITMEETILISTEST OPERAATORITEST 22
23
ÜLEVAADE LOOGILISTEST OPERAATORITEST 23
ÜLESANDED 24
STANDARDPROTSEDUURID ANDMETE SISESTAMISEKS JA VÄLJASTAMISEKS. 25
25
SISSEJUHATUS 25
STANDARDPROTSEDUURID ANDMETE VÄLJASTAMISEKS 28
STANDARDPROTSEDUURID ANDMETE SISESTAMISEKS 30
VÄLJUNDI VORMISTAMINE 33
ÜLESANDED 35
MÄRKUS TRANSLAATORITE KASUTAMISE KOHTA 35
TINGIMUSLAUSE . SUUNAMISLAUSE. VALIKULAUSE. 36
36
SISSEJUHATUS 36
TINGIMUSLAUSE 37
SUUNAMISLAUSE 39
VALIKULAUSE 40
ÜLESANDED 40
STRUKTUURSED ANDMETÜÜBID: JADA,
MASSIIV , KIRJE, FAIL. 40
40
Sissejuhatus 40
Jada. Massiiv. Massiivi mõõtmed 41
Massiivi
deklareerimine 41
43
Massiivi kasutamine 43
Kirje 44
44
Kirje deklareerimine 44
46
Kirje kasutamine 46
Fail 46
47
Faili deklareerimine 47
48
Faili kasutamine 48
ÜLESANDED 49
MÄÄRATUD KORDUS. EELKONTROLLIGA KORDUS. JÄRELKONTROLLIGA KORDUS. 49
SISSEJUHATUS 49
MÄÄRATUD KORDUS 50
EELKONTROLLIGA KORDUS 50
JÄRELKONTROLLIGA KORDUS 51
Korduslaused keeles
Pascal 52
Korduslaused keeles C 52
Korduslaused keeles Qbasic 52
KORDUSLAUSETE KASUTAMINE 53
ÜLESANDED 56
Jada järjestamine 56
Minimaalseima väärtuse leidmine
maatriksist 57
Suurima
summaga rea leidmine maatriksist 57
VIITMUUTUJA. ARVUTI MÄLU PAINDLIK KASUTAMINE 57
SISSEJUHATUS 57
VIITMUUTUJA OLEMUS 57
VIITMUUTUJA KASUTAMINE 58
Viitmuutuja kasutamine keeles Pascal 59
Viitmuutuja kasutamine keeles C 59
MÄLU PAINDLIK KASUTAMINE 60
Mälu hõivamine 60
Mälu vabastamine 61
TÜÜPILISED KOMISTUSKIVID 62
DÜNAAMILISED
ANDMESTRUKTUURID 63
Ahel ja järjekord 63
Pinumälu ehk magasinmälu 65
ÜLESANDED 67
ALAMPROGRAMMID .
PROTSEDUUR JA FUNKTSIOON 67
MILLEKS ON VAJA ALAMPROGRAMME? 67
PROTSEDUURI JA FUNKTSIOONI ERINEVUSED 68
ALAMPROGRAMMIDE KASUTAMINE 68
Pascal 69
C 70
Qbasic 71
PARAMEETER 71
GLOBAALSED JA
LOKAALSED MUUTUJAD 74
ÜLEVAADE STANDARDPROTSEDUURIDEST JA -FUNKTSIOONIDEST 75
Pascal 75
C 77
Qbasic 78
ÜLESANDED 79
Sissejuhatus 87
Struktuurprogrammeerimine 87
Objektorienteeritud programmeerimine 88
Objekt, atribuut, meetod 88
Klass 89
Kapseldumine 89
Sündmused ja
teated 90
Pärilikkus ja polümorfism 90
Mis on kasu objektorienteeritusest? 91
Objektorienteeritud maailm 91
Mida selle kursusel õpetatakse?
Esimese astme materjalid on jaotatud
12-ks teemaks, millega
kaasnevad ülesanded harjutamiseks. Nendeks teemadeks on:
Suurem sissejuhatav sõnavõtt ehk 'Milleks on vaja programmeerimist?'
Põhimõisted: andmetüüp, väärtus, konstant, muutuja , identifikaator , võtmesõna, operand, operaator. Omistamise lause.
Aritmeetiline ja loogiline avaldis.
Standardprotseduurid andmete sisestamiseks ja väljastamiseks.
Tingimuslause. Suunamislause. Valiklause.
Struktuursed andmetüübid: jada, massiiv, kirje, fail.
Määratud kordus. Eelkontrolliga kordus. Järelkontrolliga kordus.
Viitmuutuja. Arvuti mälu paindlik kasutamine.
Alamprogrammid. Protseduur ja funktsioon.
Programmide vormistamine. Identifikaatorite süstematiseerimine. Taanete kasutamine.
Programmi dokumenteerimine . Kommentaarid. Programmi projekteerimine. Programmi testimine .
Struktuurprogrammeerimise põhimõtted. Objektorienteeritud programmeerimise põhimõtted.
Esimesel tasemel kasutatakse näidetes samaaegselt kolme
programmeerimise keelt, milleks on Pascal, C ja Basic .
Siinkohal tahaks rõhutada, et antud kursuse eesmärgiks ei ole
mitte programmeerimiskeele täiuslik omandamine, vaid
programmeerimise oskuse omandamine - need kaks oskust on erinevad!
Samuti on kursuse materjalidesse peidetud soov näidata, et samasse klassi kuuluvad programmeerimiskeeled on oma olemuselt samasugused.
SISSEJUHATAV SÕNAVÕTT EHK 'MILLEKS ON VAJA PROGRAMMEERIMIST?'
PROGRAMMEERIMISE KOHT MUUDE MAAILMA ASJADE SEAS
Masinad ja nende juhtimine
Oli kord aeg, mil inimene tegi tööd vaid käsitsi. Ta võttis küll
kasutusele töövahendid oma töö kergendamiseks, kuid tänapäevases
mõttes tegi ta tööd ikkagi käsitsi. Mõningate jõudu nõudvate
tööde tegemiseks hakkas ta kasutama loomi, hiljem masinaid, kuid
ilma inimese juuresolekuta saadi hakkama vaid väga vähestes
kohtades - nii loomad kui ka masinad vajasid juhtimist. Kujutame seda
järgneva joonisega:
--------- juhtimine -----------
|
Masin | tegevus ei muuda muutuja väärtust
|
Muutuja |
| | A
B
= A 10 10 ? A -> 10 -> B
C
= A 10 10 10 A -> 10 -> C
------------------------------------------------------------------
Sellest tabelist võib näha, et konstandi väärtuse omistamisel
muutujale kirjutatakse väärtus 10 muutujanimega A tähistatud
mälupesa(de)sse. Muutuja väärtuse omistamisel teisele muutujale
toimub esiteks väärtuse 10 lugemine muutujanimega A
tähistatud mälupesa(de)st ja seejärel selle väärtuse kirjutamine
muutujanimega B tähistatud mälupesa(de)sse. See on sellise
protsessi tegelik kirjeldus. Edaspidi räägime ainult, et "muutuja
A väärtus omistatakse muutujale B".
Kellele see jutt ikkagi segasena tundus, sellel soovitan kodus
mängida järgmiste reeglite järgi:
muutujaks on tühi tikutops;
muutuja nimeks on tikutopsile peale kirjutatud täht või nimi;
väärtuseks on selline paberitükk, mis mahub tikutopsi ja mille peal on vastav arv;
tikutopsis tohib korraga olla vaid üks paberitükk;
muutujale väärtuse omistamine on samaväärne tegevusega , kus vastava arvuga paberitükk asetatakse tikutopsi, kuid vastavalt reeglile (4) võetakse sealt eelmine paberitükk välja (kui see seal oli);
muutujast väärtuse lugemine on samaväärne ühe uue paberitüki võtmisega ja sinna muutujaga samasuguse väärtuse peale kirjutamisega.
Tehes täpselt nende reeglite järgi, saate Te modelleerida
operatsioone muutujatega ilma otseselt arvutit kasutamata. Ja ärge
unustage, et kui mänguruum hakkab kitsaks jääma, siis võite ju
endale uue muutuja deklareerida (kui muidugi tikutopsid otsas ei ole
;-).
Omistamislause keeles Pascal
Keeles Pascal on omistamislause süntaks järgmine:
':='
Et eristada üksteisele järgnevaid lauseid , pannakse nende vahele
semikoolon ';',
välja arvates mõned erijuhud . Eelnev näide keeles Pascal
näeb välja niisugune:
A
:= 10;
B
:= A;
C
:= A;
Omistamislause keeles C
Keeles C on omistamislause süntaks järgmine:
'=' ';'
Eelnev näide keeles C näeb välja niisugune:
A
= 10;
B
= A;
C
= A;
Omistamislause keeles Basic
Et programmeerimiskeeli, mille nimes esineb sõna "Basic"
on suhteliselt palju ja süntaksi poolest pisut erinevaid, siis
valisin välja ühe sellise, mida levitatakse koos
operatsioonisüsteemiga MS-DOS 6.2 ja selle nimi on MS-DOS
QBasic 1.1. Samasugust süntaksit kasutab ka Visual Basic.
Keeles QBasic on omistamislause süntaks järgmine:
[
'LET' ] '='
Nurksulud eelnevas definitsioonis tähendavad, et nurksulgude vahel
olevad sümbolid võib ära jätta, need ei ole kohustuslikud.
Eelnev näide keeles QBasic näeb välja niisugune:
A
= 10
B
= A
C
= A
ÜLESANDED
Selle teema kohta on erinevaid ülesandeid küllaltki raske välja
mõelda, mingis mõttes on nad ikka sarnased ja eesmärk on neil
samuti ühine - kontrollida, kas Te olete muutuja mõistest aru
saanud või mitte. Väga tahaksin rõhutada, et kui Teil mõnest
mõistest arusaamisega raskusi on, siis tingimata küsige kellegi
oskaja käest nõu.
See ülesanne on mõnes mõttes klassikaline, kuid ma ei tahtnud esitada seda kui näidet. Niisiis, on antud kaks muutujat nimedega A ja B ning väärtustega vastavalt 10 ja 20 (või mis tahes). Mida peab tegema, et vahetada muutujate A ja B väärtused omavahel ära?
Kui Te jääte selle ülesande lahendamisel hätta, siis siin on väike vihje.
On antud viis muutujat A, B, C, D ja E ning nende väärtused vastavalt 7, 1, 4, 9 ja 2. Tehke vastavad muutujate väärtuste omistamised selleks, et muutujate A kuni E väärtused oleksid kasvavas järjekorras. Leidub lahendus, mis nõuab 5 omistamislauset.
See ülesanne on eriti neile, kes esimesest kahest ülesandest mängleva kergusega jagu said. Mis muidugi ei tähenda, et teised seda lahendada ei võiks ;-)
Ehitati selline arvuti, millel on andmete hoidmiseks väga suur tekstirea kujuline mälu. Sisendandmed pannakse enne töö algust sellesse ritta ja tulemused võetakse sealtsamast tekstireast pärast programmi töö lõppemist. Sellise arvuti programm asub eraldi ja koosneb lausetest kujul
'(' ',' sqrt (a^2+b^2)
Operand ja operaator
Avaldise väärtuse leidmise puhul tuleb meil tihti rääkida tehete ehk operatsioonide sooritamisest. Sellest tuleneb ka kaks uut mõistet
- operand ja operaator. OPERAATOR on see, kes või mis sooritab talle
spetsiifilise operatsiooni. OPERAND on see väärtus, millega
operaator oma operatsiooni sooritab.
Matemaatikas on üheks tuntumaks operaatoriks plussmärk ehk liitmisoperaator . Nii nagu nimigi ütleb, on plussmärgi tegevuseks
kahe väärtuse kokkuliitmine. Me ütleme "kaks pluss kolm on
viis" ja mõistame selle lause all seda, et kui liita kokku
väärtused 2 ja 3, siis tulemuseks saame väärtuse 5.
Plussmärgi ja liitmisoperaatori samastamine tuleneb meie
kooliharidusest. Kui õpetaja koolis esimesest klassist alates
õpetaks, et pluss tähistab kahe arvu kõrvutiasetamist ehk "2
+ 3 on 23", siis kooli lõpetades te selle peale enam ei mõtleks
ja võtaksite seda kui iseenesest mõistetavat tõsiasja.
Liitmisoperaatorit võib kujutada ka funktsioonina LIIDA(a,b). Siis
on täiesti samaväärne, kas me kirjutame
1
+ 2 + 3
või
LIIDA(1,
LIIDA(2,3)),
tulemuseks on mõlemal juhul väärtus 6 (funktsiooni LIIDA väärtus
arvude 2 ja 3 puhul on 5).
Operaatoreid on mitmesuguseid. Meile tuntumad on operaatorid , mis
nõuavad kahe operandi olemasolu. Esineb ka ühe operandiga
operaatoreid. Näiteks arvu astendamise operaator on kahe
operandiga ( 2^10 ), arvu märgi muutmise operaator aga ühe
operandiga ( -5 ). Eelmises teemas käsitletud omistamise märk on ka
operaatori tunnustega. Seda võib nimetada omistamisoperaatoriks,
mille tegevuseks on avaldise väärtuse kirjutamine muutujasse.
Programmeerimiskeeltes eristatakse kahte liiki avaldisi -
aritmeetilisi avaldisi, mille tulemuse väärtuseks on arv ja
loogilisi avaldisi, mille tulemuseks on tõeväärtus.
Aritmeetiline
avaldis
Aritmeetilises avaldises kasutatakse eeskätt arvutüüpi
andmeobjekte ja aritmeetilisi tehtemärke. Ka võib aritmeetilises
avaldises kasutada arvutüüpi funktsioone. Kõik eespool toodud
näited avaldiste kohta on olnud aritmeetilised avaldised .
Loogiline
avaldis
Loogiline avaldis sisaldab ühte või enamat loogilist operaatorit ja
võib tihti sisaldada aritmeetilisi avaldisi. Matemaatikast tuntud
loogiline avaldis on võrratus, mille puhul on tulemuseks samuti
tõeväärtus:
2
tõene
2
= 8 ==> väär
x
+ 3 > 10 ==> tõene, kui x >= 8, muidu väär
Lisaks operaatoritele, mida kasutatakse operandide võrdlemiseks, on
loogilistes avaldistes kasutusel loogikatehted JA (loogiline korrutamine ehk konjunktsioon ), VÕI (loogiline liitmine ehk disjunktsioon ), POLE (loogiline
eitus ehk negatsioon) ja mõned teised. Need tehted jäävad
kahjuks väljapoole meie koolide matemaatika programmi, kuid
programmeerimine ilma neid kasutamata läbi ei saa. Loogikatehetest
saab kõige paremini aru, kui õppida selgeks vastavad
tõeväärtustabelid ( analoogia korrutustabeliga, see tuli ka
pähe õppida):
JA
| tõene | väär | Selgituseks :
------################# (tõene JA tõene) on tõene
tõene
# tõene | väär # (tõene JA väär) on väär
------#-------+-------# (väär JA tõene) on väär
väär # väär | väär # (väär JA väär) on väär
------#################
VÕI | tõene | väär | Selgituseks:
------################# (tõene VÕI tõene) on tõene
tõene
# tõene | tõene # (tõene VÕI väär) on tõene
------#-------+-------# (väär VÕI tõene) on tõene
väär # tõene | väär # (väär VÕI väär) on väär
------#################
POLE
| tõene | väär | Selgituseks:
------################# (POLE tõene) on väär
#
väär | tõene # (POLE väär) on tõene
------#################
Seega, loogiline avaldis kujul
(A
10)
on tõene ainult siis, kui mõlemad tingimused on tõesed.
ÜLEVAADE ARITMEETILISTEST OPERAATORITEST
Alljärgnevalt teen ma väikese ülevaate aritmeetilistest
operatsioonidest. See ülevaade ei ole kaugeltki täielik, kuid see
ei olegi antud juhul eesmärgiks. Operatsioonid on järgnevas tabelis
esitatud prioriteedi (tehete järjekorra tähtsuse) kahanemise
järjekorras. See tähendab, et märgi muutmine tehakse alati enne
kui astendamine või korrutamine ja korrutamine omakorda eelneb
liitmisele või lahutamisele.
Sellest tulenevalt on avaldise 2 + 7 * 3 väärtuseks 23 mitte 27.
Operatsiooni
nimetus | operandi tüüp | tulemuse tüüp | operande
------------------------+------------------+---------------------+---------
märgi
muutmine | täisarv, reaalarv | sama, mis operandil | 1
astendamine | täisarv,reaalarv | sama, mis operandil | 2
korrutamine | täisarv,reaalarv | sama, mis operandil | 2
jagamine | täisarv,reaalarv | sama, mis operandil | 2
täisarvuline
jagamine | täisarv | täisarv | 2
jagamise jäägi leidmine | täisarv | täisarv | 2
nihutamine paremale | täisarv | täisarv | 2
nihutamine
vasakule | täisarv | täisarv | 2
liitmine | täisarv,reaalarv | sama, mis operandil | 2
lahutamine | täisarv,reaalarv | sama, mis operandil | 2
Kui operatsioonist võtavad osa nii täisarvud kui ka reaalarvud ,
siis harilikult on tulemuseks reaalarv.
Aritmeetilised operaatorid keeles
Pascal
Operatsiooni
nimetus | operandi tähis
------------------------+---------------
märgi
muutmine | -
astendamine | puudub, kasutatakse funktsioone: sqr(x)=>x ruudus
korrutamine | *
jagamine | /
täisarvuline
jagamine | DIV
jagamise
jäägi leidmine | MOD
nihutamine
paremale | SHR ; (5 SHR 1) on sama, kui (5 DIV 2)
nihutamine
vasakule | SHL ; (5 SHL 1) on sama, kui (5 * 2)
liitmine | +
lahutamine | -
Aritmeetilised operaatorid keeles C
Operatsiooni
nimetus | operandi tähis
------------------------+---------------
märgi
muutmine | -
astendamine | puudub, kasutatakse funktsiooni: pow(x,y)
korrutamine | *
jagamine | /
täisarvuline
jagamine | /
jagamise
jäägi leidmine | %
nihutamine
paremale | >>
nihutamine
vasakule | =
väiksem
kui | =
väiksem
kui | =
väiksem
kui | 100% ja 350 tonni --> 12,5%.
Nende andmete põhjal kirjutame võrrandi, kus küsitud koguse
tähistame tähega K:
K 100
---
= ---- ehk (K/350)=(100/12,5).
350 12,5
Sellest võrrandist avaldame K:
K
= (100/12,5)*350 = 2800.
Seega on konkreetse ülesande vastus 2800 tonni.
Ja kus on siin programmeerimine? Asi on nimelt selles, et arvuti
ei ole võimeline sellist ülesannet lahendama. Küll aga on
arvuti võimeline etteantud programmi alusel arvutusi tegema. Seega
antud ülesannet lahendav programm oleks järgmine:
P r o g r a m m N1.1
K
= (100/12.5)*350
VÄLJASTA
K
Või saab kasutada ka üherealist programmi:
P r o g r a m m N1.2
VÄLJASTA
(100/12.5)*350
Seega, Teie lahendate ülesannet, arvuti teostab arvutused -
selline on tööjaotus. Selles väikeses üherealises programmis tähistab sõna 'VÄLJASTA' standardprotseduuri
sellele sõnale järgneva väärtuse väljastamiseks väljundseadmele.
Täiesti kohane on küsimus, et milleks on vaja sellist programmi,
mis lahendab ainult üht konkreetset ülesannet?
Õigustatud on selline programm siis, kui kalkulaatorit pole
käepärast ja peast arvutada ei viitsi. Palju kasulikum on aga
selline programm, mis lahendab selle ülesande kõikvõimalikke
variante, see tähendab ülesannet, mille sõnastus võiks olla
järgmine:
NÄIDE 2.
Ü l e s a n n e
Saadava suhkru mass moodustab P % töödeldava suhkrupeedi
kogusest. Kui palju on vaja suhkrupeeti X tonni suhkru
saamiseks?
L a h e n d u s
Avaldame K analoogiliselt eelmisele näitele:
K
= (100/P)*X
Selleks, et leida suurus K, on meil vaja teada suurusi P
ja X. Programmeerimise kontekstis öelduna tähendab see seda,
et muutuja K väärtuse leidmiseks on meil tarvis omistada
muutujatele P ja X väärtused. Eelmise näitega
samaväärse programmi saame, kui omistame neile muutujatele
eelmises ülesandes püstitatud väärtused:
P r o g r a m m N2.1
P
= 12.5
X
= 350
K
= (100/P)*X
VÄLJASTA
K
Lisaks omistamislausele leidub veel teinegi võimalus muutujale
väärtuse omistamiseks - see on väärtuse sisestamine standardprotseduuri abil. Tähistame sellist protseduuri sõnaga
' SISESTA ' ja kirjutame programmi, mis aitab meil lahendada kõiki
teise näite alla kuuluvaid ülesandeid:
P r o g r a m m N2.2
SISESTA
P
SISESTA
X
K
= (100/P)*X
VÄLJASTA
K
Standardprotseduur 'SISESTA' töötab harilikult järgmise algoritmi järgi:
Loeme kokku klaviatuurilt sisestatud sümbolid, kuni vajutatakse reavahetuse klahvi (' Return ' või 'Enter').
Kui sisestatud sümbolid moodustavad väärtuse, mis sobib kokku protseduuri väljakutsega kaasa antud muutuja tüübiga, siis omistame saadud väärtuse sellele muutujale, vastasel korral teatame kasutajale, et sisestatud väärtusel ei ole sobiv andmetüüp.
Tegelikes programmeerimisekeeltes on see algoritm tihti keerulisem
kui eelkirjeldatu, kuid üldine põhimõte on sama.
Kõiki programme võib üldjuhul vaadelda koosnevana kolmest osast:
1) andmete sisestamine;
2) andmete töötlemine;
3)
andmete väljastamine.
Erandjuhtudel võib olla programm ilma andmesisestuseta, nagu programmid N1.1
ja N1.2.
Veelgi harvemini võib tulla ette programme, millel ei ole andmete
väljastamist. Selline olukord viitab kasutule programmile, sest mida
see ka ei teeks , tulemusi selline programm ei esita.
Vaatleme nüüd järgnevalt, milliseid võimalusi andmete
sisestamiseks ja väljastamiseks pakuvad kursusel kasutatavad
programmeerimiskeeled ning mida andmete sisestamine ja väljastamine
tegelikult tähendavad.
STANDARDPROTSEDUURID ANDMETE VÄLJASTAMISEKS
Andmete väljastamise olemus
Andmete väljastamisel leitakse etteantud avaldise väärtus ja
kirjutatakse see väljundvoogu.
VÄLJUNDVOOG on programmeerimises kasutatav üldistus kõigi andmete
kohta, mis liiguvad programmist väljundseadmele. Tüüpiliselt on
väljundvoog suunatud kuvari ekraanile . Enamikus
programmeerimiskeeltest loetakse seda standardseks väljundvooks
ja kui ei ole kuidagi teistmoodi defineeritud, siis kasutatakse seda.
Kuid väljundvoo sihtpunktiks võib olla ka kettal paiknev fail või
printer.
Andmete väljastamine keeles Pascal
Väljastamiskäsu süntaks keeles Pascal on järgmine:
'WRITE'
'(' ')' |
'WRITELN'
[ '(' ')' ]
avaldiste_loetelu
-> [ ',' ]
Protseduuride 'Write' ja 'WriteLn' erinevus seisneb selles, et
viimane viib väljastamise järjekorra uuele reale ehk teeb
reavahetuse.
P r o g r a m m N1.1.P
Program N1_1_P;<
K
: Real ;
Begin
K
:= (100/12.5)*350;
Writeln(K);<
Nagu Te ehk juba taipasite, kirjutatakse keeles Pascal kommentaarid
loogeliste sulgude ( '{' , '}' ) vahele.
Andmete väljastamine keeles C
Väljastamiskäsu süntaks keeles C on järgmine:
'printf'
'(' ',' ')' ';'
Keeles C tuleb tähele panna, et suured ja väikesed tähed
on translaatori jaoks erinevad. Nii võib defineerida muutujad
nimedega 'k' ja 'K' ning kasutada neid samaaegselt.
Sellegipoolest ei ole see soovitatav, sest võib põhjustada
valestimõistmist ja programmeerijapoolseid vigu. Küll aga tuleb
veateadete korral, mis väidavad muutuja 'p' puudumist,
kontrollida, kas ei peaks 'p' asemel olema kasutatud muutujat
'P'. Selliseid näpukaid tuleb kõigil ette, eriti aga
algajatel.
P r o g r a m m N1.1.C
# include /* Ütleme, et on vajalik lugeda päisfaili
' stdio .h'.
Selles asuvad C standartsete sisend -
väljundfunktsioonide
kirjeldused. /*
main() /* Põhiprogrammi algus */
float
K; /* Ütleme, et K on reaalarvu tüüpi muutuja. */
K
= (100/12.5)*350; /* 'Andmetöötlus' */
printf("%f",
K); /* Väljasta tulemus */
} /* Põhiprogrammi lõpp. */
Kommentaarid kirjutatakse sümbolipaaride '/*' ja '*/' vahele.
Kontrollstringi abil on võimalik kujundada väljundit. Sellest tuleb juttu allpool.
Andmete väljastamine keeles Qbasic
Väljastamiskäsu süntaks keeles QBasic on järgmine:
' PRINT ' |
'WRITE'
avaldiste_loetelu
-> [ ( ',' | ';' ) ]
Väljastusprotseduur 'Write' erineb protseduurist 'Print' selle
poolest, et kirjutab väljastatud väärtuste vahele komad ja
stringide ümber jutumärgid. Käsuga 'Write' väljastatud andmete
formaat on kokkusobiv sisestusprotseduuri 'Input' sisendformaadiga.
P r o g r a m m N1.1.B
K
= (100/12.5)*350 ' Andmetöötlus
print
K ' Väljasta tulemus
Kommentaarid kirjutatakse rea lõppu ühekordse apostroofi järele.
STANDARDPROTSEDUURID ANDMETE SISESTAMISEKS
Andmete sisestamise olemus
Nagu ma juba eespool märkisin, on andmete sisestamine veel üheks meetodiks muutujale väärtuse omistamisel. Kui omistamislause saab
väärtuse avaldiselt, siis sisestamisprotseduur saab väärtuse
sisendandmete voost ehk sisendvoost.
SISENDVOOG on programmeerimises kasutatav üldistus kõikide
programmi sisestatavate andmete kohta. Tüüpiliselt saabub
sisendvoog klaviatuurilt. Enamikus programmeerimiskeeltest loetakse
seda standardseks sisendvooks ja kui ei ole kuidagi teistmoodi
defineeritud, siis kasutatakse seda. Kuid sisendvoo lähtepunktiks
võib olla ka kettal paiknev andmefail või mõni sisendseade.
Iga sisestamisprotseduuri väljakutse loeb sisendvoost järgmise
hulga informatsiooni ja omistab selle etteantud muutujale. Sissejuhatuses esitatud programmis N2.2
käsu 'SISESTA P' tegevust võib kirjeldada järgmiselt:
1) Loeb kasutaja klahvivajutusi kuni vajutatakse klahvi [Enter]
(mõnel klaviatuuril on selleks [Return]). Iga klahvivajutusega
kaasneb vastava sümboli väljastamine kuvari ekraanile (kuid on ka
selliseid sisestusprotseduure, mis sümboleid ei väljasta).
2) Teisendab kogutud klahvivajutused väärtuseks. Antud näite
korral me eeldasime, et vajutati ainult punkti ja numbreid
tähistavatele klahvidele, seega on sisestatud väärtus reaalarvu
tüüpi.
3) Omistab saadud väärtuse muutujale P.
Sisendprotseduur võib ühe väljakutse ajal sisestada väärtused ka
mitmele muutujale. Programmi N2.2 võib kirja panna ka järgmisel
viisil:
P r o g r a m m N2.3
SISESTA
P, X
K
= (100/P)*X
VÄLJASTA
K
Mõnedes programmeerimiskeeltes on kasutajaga dialoogi pidamise
huvides võimaldatud enne muutujasse väärtuse sisestamist
väljastada kasutajale viip, mis võib kirjeldada kasutajalt
oodatavat tegevust. Viibaks on sellisel juhul stringikonstant. Toon
jällegi näite N2.2 baasil:
P r o g r a m m N2.4
SISESTA
"Palun sisesta saagikuse protsent: ", P
SISESTA
"Palun sisesta vajalik kogus: ", X
K
= (100/P)*X
VÄLJASTA
K
Kui sisestatud väärtuse tüüp ja muutuja tüüp ei lange kokku ega
ole ka vaikimisi teisendatav (näiteks arv 5 on küll täisarv, aga
selle võib teisendada ka reaalarvuks 5.0 ja omistada reaalarvu tüüpi
muutujale), siis sõltuvalt programmeerimiskeelest püütakse
tekkinud situatsioonist üle saada kas vea teatamise ja töö
lõpetamisega või võimaldatakse kasutajal veelkord väärtus
sisestada.
Andmete sisestamine keeles Pascal
Sisestamiskäsu süntaks keeles Pascal on järgmine:
'READ'
'(' ')' |
'READLN' [ '(' ')' ]
muutujate_loetelu
-> [ ',' ]
P r o g r a m m N2.3.P
Program
N2_3_P;<
P,
X, K : Real;<
Read(P,
X);
K
:= (100/P)*X;
Writeln(K);<
Viiba esitamist keele Pascal standardses sisestusprotseduuris ei ole
ette nähtud. Selleks tuleb kasutada väljastusprotseduuri abi.
Sisestusprotseduur READ loeb sisendvoost üksteisele järgnevaid
sümboleid ja ei arvesta nende paiknemist ridadel. See tähendab, et
käsk READ(A,B,C), kus A, B ja C on täisarvutüüpi muutujad, loeb
ühesuguse tulemusega mõlemaid sisestusvariante:
1)
12
569 -5
2)
12
569
-5
Sisestusprotseduur READLN loeb sisendvoost muutujatele vajalikud
väärtused ja viib sisselugemise järjekorra edasi järgmisele
"reale". Seega käsk READLN(A,B) loeb eelnevalt esitatud
esimesest sisestusvariandist väärtused 12 ja 569 ning jätab
väärtuse -5 tähelepanuta. Teises sisestusvariandis lõpetab see
käsk andmete sisestamise enne väärtuse -5 sisestama hakkamist.
Andmete sisestamine keeles C
Sisestamiskäsu süntaks keeles C on järgmine:
'scanf'
'(' ',' ')'
muutuja_aadresside_loetelu
->
[ ',' ]
muutuja_aadress
-> '&' |
P
r o g r a m m N2.3.C
#include /* Ütleme, et on vajalik lugeda päisfaili
'stdio.h'.
Selles asuvad C standartsete sisend-
väljundfunktsioonide
kirjeldused. /*
main() /* Põhiprogrammi algus */
float
P, X, K; /* Ütleme, et P, X ja K on reaalarvu tüüpi. */
scanf("%f%f",
&P, &X); /* Sisesta P ja X */
K
= (100/P)*X; /* 'Andmetöötlus' */
printf("%f",
K); /* Väljasta tulemus */
} /* Põhiprogrammi lõpp. */
Viiba esitamist keele C standardses sisestusprotseduuris ei ole ette
nähtud. Selleks tuleb kasutada väljastusprotseduuri abi.
Kontrollstringi abil on võimalik sisestada väga keerulise
struktuuriga sisendinformatsiooni ja näidata täpselt, kuidas saadud
informatsiooni interpreteerida. Esialgu on piisav, kui teame järgmisi
kontrollstringi kujusid:
int
i; scanf("%d", &i); /* sisestab täisarvu */
float
r; scanf("%f", &r); /* sisestab ühekordse täpsusega
reaalarvu */
char c; scanf("%c", &c); /* sisestab sümboli */
char
s[30]; scanf("%s", s); /* sisestab stringi */
Keeles C leidub veel suurel hulgal igasuguseid spetsiifilisi
sisestusfunktsioone, kuid neid ma tutvustan kunagi hiljem.
Andmete sisestamine keeles QBasic
Sisestamiskäsu süntaks keeles QBasic on järgmine:
'INPUT'
[ ';' ] [ ( ';' | ',' ) ] |
'LINE
INPUT' [ ';' ] [ ';' ]
P r o g r a m m N2.3.B
input
P, X ' Sisesta P ja X
K
= (100/P)*X ' Andmetöötlus
print
K ' Väljasta tulemus
Sellele programmile andmeid sisestades peab teadma, et arvud tuleb
kirjutada ühele reale ja eraldada üksteisest komaga .
Keeles Basic on üldiselt lubatud kasutada deklareerimata
lihtmuutujaid. Antud programmis N2.3.B tekitatakse muutujad P ja X
sisestuskäsu töötamise ajal ja nende tüüp määratletakse
vastavalt sisestatud väärtuse tüübile. Kord juba tekitatud
muutuja tüüpi hiljem muuta ei saa.
P r o g r a m m N2.4.B
input
"Palun sisesta saagikuse protsent: ", P ' sisesta P
input
"Palun sisesta vajalik kogus: ", X ' sisesta X
K
= (100/P)*X ' Andmetöötlus
print
K ' Väljasta tulemus
Sisestamiskäsku kirjutades on süntaksi järgi võimalik kasutada
kas koma või semikoolonit. Seda, mis toimub ühe või teise eraldaja kasutamise korral, on õpetlik endal järele proovida.
VÄLJUNDI VORMISTAMINE
Mis on väljundi vormistamine?
Tihti on vaja vormistada väljastatav informatsioon mingisugusele
nõutud kujule . Kõige tavalisem on andmete esitamine tabelina.
Põhjuseks on tabelina esitatud andmete parem loetavus. Sageli
soovitakse näha reaalarvulisi andmeid ühesuguse hulga kohtadega pärast koma jne. Selleks on paljudes programmeerimiskeeltes
väljastamisprotseduurile lisatud juba spetsiaalsed vormistamise
vahendid.
Väljundi vormistamise võimalused
keeles Pascal
Väljastusprotseduurile 'Write' etteantud avaldise võib kirja panna
ka järgmise süntaksi järgi:
[ ':' [ ':' ]]
Sellisele süntaksile vastavad väljastuskäsud ja tulemused võivad
olla järgmised:
writeln('|',123.8,'|'); | 1.2380000000E+02|
writeln('|',123.8:8,'|'); | 1.2E+02|
writeln('|',123.8:8:2,'|'); | 123.80|
writeln('|',123.8:8:0,'|'); | 124|
writeln('|',123.8:-8:0,'|'); |124 |
writeln('|','Tere':10,'|'); | Tere|
writeln('|','Tere':-10,'|'); |Tere |
Nagu toodud näidetest võib tähele panna, tähendab negatiivne
väljundi pikkus hoopis andmete paigutamist välja vasakpoolsesse
otsa.
Väljundi vormistamise võimalused
keeles C
Kõik väljastusprotseduuri vormistamise võimalused on seotud
kontrollstringiga. Järgnevalt püüan ma anda lühikese ülevaate
keelest, mille abil väljundit kontrollstringis vormistatakse.
Kontrollstringis saab kasutada järgmisi sümbolipaare vastava mõiste
tähenduses:
\a hoiatus, genereerib helisignaali
\b backspace , samm tagasi koos kustutamisega
\c rea väljastamine ilma reavahetuseta
\f form- feed , lehekülje lõpetamine
\n new-line, reavahetus
\r carriage return, väljastamisjärje toomine rea algusesse
\t tabulaator
\v vertikaalne tabulaator
\' apostroof
\\ backslash, tagurpidine kaldkriips
\n väljastab 8-bitise sümbol, mille ASCII kood on kuni
neljakohaline
kaheksandsüsteemi
arv n ja mille esimene number on 'null'.
Märgiga '%' alustatakse andmete teisendamise informatsiooni blokki,
mille üldine süntaks on:
'%'
[ ][ ][ '.' ]
kus
lipud
-> '-' | '+' | ' ' | '#'
teisendustähis
-> 'd' | 'i' | 'o' | 'u' | 'x' | 'X' | 'f' | 'e' | 'E' |
'g'
| 'G' | 'c' | 's'
- teisenduse resultaat paigutatakse välja vasakusse otsa;
+ teisenduse arvuline resultaat omab alati kas '+' või '-'
märki;
# kasutatakse 'alternatiivset vormi'.
d,i täisarv väljastatakse kui märgiga täisarv;
o täisarv väljastatakse kui märgita kaheksandsüsteemi arv;
u täisarv väljastatakse kui märgita täisarv;
x,X täisarv väljastatakse kui märgita kuueteistkümnendsüsteemi
arv;
f reaalarv väljastatakse normaalsel kujul ([-]nnn.nnnn);
e,E, reaalarv väljastatakse eksponendi abil kujul ([-]n.nnne(+|-)nn);
g,G
c väärtuse esimene bait väljastatakse kui sümbol;
s väärtust vaadeldakse kui stringi ja väljastatakse kuni
stringi lõpu tunnuseni.
Järgnevalt mõned näited kontrollstringi kasutamisest:
printf("%#o,
%#x, %#X, %#f, %#g, %#e\n", 123, 123, 123, 123, 123, 123);
Tulemus
-> 0173, 0x7b, 0X7B, 123.000000, 123.000, 1.230000e+02
printf("%.6d,%10.6d,%.6f,%.6e,%.6s\n",
123, 123, 1.23, 123.4, "MoreThan");
Tulemus
-> 000123,000123,1.230000,1.234000e+02,MoreTh
Väljundi vormistamise võimalused
keeles QBasic
Väljastamiskäsu 'PRINT' harilike vormistamisvahendite hulka kuulub
koma ja semikooloni sihipärane kasutamine. Kui on vaja kasutada
täpsemat väljundformaati, siis on abiks järgmine käsk:
'PRINT'
'USING' ';'
Formaadikirjeldus on spetsiaalne string , mis võib sisaldada järgmisi
sümboleid:
Numbriliste väärtuste vormistamine
# Numbri koht.
- Kui on paigutatud numbrikohtade taha, siis väljastab
negatiivse arvu märgi ka arvu taha.
. Arvu koma koht.
, Kui on paigutatud komakohast vasakule, siis väljastab koma iga
kolme numbri järel.
$$ Väljastab numbri ette märgi '$'.
+ Numbri märgi koht.
** Väljastab arvu ette jäävatele kohtadele märgid '*'.
^^^^ Väljastab arvu eksponentsiaalsel kujul.
**$ Kombineerib käskude ** ja $$ mõju.
Stringide vormistamine
& Väljastab terve stringi.
\
\ Väljastab esimesed n sümbolit, kusjuures n on kaldkriipsude
vahel
olevate
tühikute arv + 2.
! Väljastab ainult esimese sümboli stringist.
ÜLESANDED
1. Kirjutage programm järgmise ülesande lahendamiseks.
1.a Milline oli korvpallivõistkonna visketabavuse protsent, kui
78-st pealeviskest tabas 43?
1.b Milline oli korvpallivõistkonna visketabavuse protsent, kui N
pealeviskest tabas T viset ? Vormista väljund selliselt , et vastuse
täpsus oleks kolm kohta pärast koma.
2. Kirjutage programm, mis loeb sisse teist järku determinandi
elemendid ja arvutab determinandi väärtuse. (Teist järku determinant on võrdne peadiagonaali elementide korrutise ja
kõrvaldiagonaali elementide korrutise vahega, s.t.
|
a1 a2 |
|
b1 b2 | = a1*b2 - a2*b1. )
Väljastada ekraanile nii determinant tabeli kujul kui ka
determinandi väärtus täpsusega 2 kohta pärast koma.
MÄRKUS TRANSLAATORITE KASUTAMISE KOHTA
1. Turbo Pascal 5.0, 5.5, 6.0, 7.0
1) Avage uus fail menüüvalikuga "FILE/NEW"
2) Kirjutage programmi tekst ja salvestage see Teile sobiva nimega,
laiendiks peaks jääma '.PAS'.
Kasutage selleks "FILE/SAVE"
või klahvi [F2].
3) Kompileerige programm ("COMPILE/MAKE" või [F9]).
4) Käivitage programm menüüvalikuga "RUN/RUN" või
klahviga [Ctrl]+[F9]
2. Turbo C, Turbo C++, GCC, CC
1) Kirjutage valmis programmi tekst. Kui kasutate Turbo C[++]
keskkonda, siis kehtib sama jutt, mis Turbo Pascali puhul. UNIX 'i
keskkonnas kasutage tekstieditori, mida Te tunnete. Laiendiks peaks
failil jääma '.C'.
2) Kompileerige programm. Turbo keskkonnas kasutage käske MAKE või BUILD , UNIX'i keskkonnas peaks abiks olema käsk 'make failinimi'
(ilma laiendita!).
3) Käivitage programm. Turbo keskkonnas saab kasutada valikut "RUN",
UNIX'is tuleb programm kutsuda välja nimepidi.
3. MS Qbasic 1.0
1) Avage uus fail menüüvalikuga "FILE/NEW"
2) Kirjutage programmi tekst ja salvestage see Teile sobiva nimega,
laiendiks peaks jääma '.BAS'. Kasutage selleks "FILE/SAVE".
3) Käivitage programm menüüvalikuga "RUN/START" või
klahviga [ Shift ]+[F5]
TINGIMUSLAUSE. SUUNAMISLAUSE. VALIKULAUSE.
SISSEJUHATUS
Oma igapäevases elus teeme me kas teadlikult või alateadlikult
tuhandeid valikuid ja võtame vastu otsuseid edaspidiseks tegevuseks.
Meie valikud sõltuvad nendest kriteeriumidest, mida me oleme enda
jaoks kujundanud kogu eelneva elu jooksul. Kriteeriumid võivad olla
seotud meie teadmistega, tõekspidamistega, seadustega, kasutada
olevate vahenditega, eesmärkidega, hetke meeleoluga jne. Mingisugust
valikut tehes kasutame me üht kriteeriumi selleks, et hinnata
valikust tulenevate tagajärgede kasulikkust, tulemuslikkust,
meeldivust ja teisi aspekte.
Programmeerimises on valiku tagamaad teistsugused kui elus. Programmi
kirjutades me teame valiku tagajärgi täpselt (need kujundame ja
kirjutame ju ise) ja seega peame keskendama oma tähelepanu nendele kriteeriumidele , mis on valiku tegemise aluseks. Programmeerimises
kasutatavate valikutega on lihtsam kui elus ettetulevatega - nad on
formaliseeritavad ehk üheseltmõistetavalt kirja pandavad.
Programmis ei saa kasutada valiku tegemiseks tingimust kujul 'Kui
see värv on meeldiv, siis ...', sest meeldivuse hindamine on
mitteformaliseeritav tegevus.
Järgnevalt püüan ma anda ülevaate erinevatest valikute
realiseerimise võimalustest meie poolt vaadeldavates
programmeerimiskeeltes.
TINGIMUSLAUSE
Väga tihti on programmi kirjutamisel vaja käskude täitmise
järjekord suunata sõltuvalt mingisuguste muutujate hetkeväärtustest
kahte erinevat rada mööda. Sellist muutujate väärtusi
kontrollivat avaldist nimetatakse TINGIMUSEKS. Kujutame sellist
programmilõiku blokk -skeemina :
v
--------
+ / \ -
----------
| \ / |
v -------- v
------------ ------------
| | | |
|
tegevus1 | | tegevus2 |
| | | |
------------ ------------
| |
----------------------
v
Seega, kui TINGIMUS on täidetud, järgneb TEGEVUS1, vastasel korral
TEGEVUS2. Piltlikult öeldes toimub käskude jada hargnemine ,
mistõttu tingimuslauset nimetatakse ka HARGNEMISLAUSEKS (-käsuks).
TINGIMUSLAUSE on programmi juhtkonstruktsioon, mis võimaldab
vastavalt etteantud loogilise avaldise väärtusele suunata programmi
täitma kas üht või teist programmiharu.
Tingimuslause üldine süntaks on järgmine:
'KUI' 'SIIS'
tegevus1
[
'MUIDU'
tegevus2
]
'KUILÕPP'.
tingimus
-> .
tegevus
-> .
lausete
jada -> [ ].
NÄIDE 1.
Ü l e s a n n e
Kirjutada programm protsentarvutuse ülesannete lahendamiseks.
Protsentarvutuse kolmeks põhiülesandeks on:
1) Osamäära M leidmine terviku T ja osa O järgi ehk kahe arvu
suhte väljendamine protsentides;
2) Osa O määramine protsendi M ja terviku T järgi;
3) Terviku T määramine, kui on teada protsent M ja vastav osa O.
L a h e n d u s
Esimeseks probleemiks on meie jaoks see, kuidas saada aru, millist
ülesandeliiki kolmest eelnimetatust kasutaja soovib lahendada.
Lihtsaimaks lahenduseks on seda küsida otse kasutaja käest, esitades eelnevalt ekraanile pakutavad võimalused ja nendele
vastavad koodid, milleks võivad olla numbrid 1, 2 ja 3.
Seejärel küsime vastavalt kasutaja poolt tehtud valikule ülesandes
antud väärtused ja arvutame otsitava väärtuse.
P r o g r a m m N1.1
VÄLJASTA
"PROTSENTARVUTUSED"
VÄLJASTA
"[1] Osamäära M leidmine terviku T ja osa O järgi"
VÄLJASTA
"[2] Osa O määramine protsendi M ja terviku T järgi"
VÄLJASTA
"[3] Terviku T määramine protsendi M ja vastav osa O järgi"
SISESTA
"Palun sisesta vajalik ülesandetüüp : ", N
KUI
N = 1 SIIS
SISESTA
"Palun sisesta terviku väärtus : ", T
SISESTA
"Palun sisesta osa väärtus : ", O
VÄLJASTA
"Osamäär on "; O/T*100; "%"
MUIDU
KUI
N = 2 SIIS
SISESTA
"Palun sisesta terviku väärtus : ", T
SISESTA
"Palun sisesta protsendi väärtus : ", M
VÄLJASTA
"Osa väärtus on "; T/100*M
MUIDU
KUI
N = 3 SIIS
SISESTA
"Palun sisesta protsendi väärtus : ", M
SISESTA
"Palun sisesta osa väärtus : ", O
VÄLJASTA
"Terviku väärtus on "; O/M*100
KUILÕPP
KUILÕPP
KUILÕPP
Toodud näites on üks kahest programmiharust jagatud veelkord kaheks
ja saadud sellega kokku kolm võimalikku haru. Sellesama programmi
võib kirja panna ka üksteisele järgnevate valikulausete jadana:
P r o g r a m m N1.2
VÄLJASTA
"PROTSENTARVUTUSED"
VÄLJASTA
"[1] Osamäära M leidmine terviku T ja osa O järgi"
VÄLJASTA
"[2] Osa O määramine protsendi M ja terviku T järgi"
VÄLJASTA
"[3] Terviku T määramine protsendi M ja vastav osa O järgi"
SISESTA
"Palun sisesta vajalik ülesandetüüp : ", N
KUI
N = 1 SIIS
SISESTA
"Palun sisesta terviku väärtus : ", T
SISESTA
"Palun sisesta osa väärtus : ", O
VÄLJASTA
"Osamäär on "; O/T*100; "%"
KUILÕPP
KUI
N = 2 SIIS
SISESTA
"Palun sisesta terviku väärtus : ", T
SISESTA
"Palun sisesta protsendi väärtus : ", M
VÄLJASTA
"Osa väärtus on "; T/100*M
KUILÕPP
KUI
N = 3 SIIS
SISESTA
"Palun sisesta protsendi väärtus : ", M
SISESTA
"Palun sisesta osa väärtus : ", O
VÄLJASTA
"Terviku väärtus on "; O/M*100
KUILÕPP
Midagi on nendel programmidel siiski sisuliselt erinevat. Programmi
töö tulemuses see ei kajastu, kuid kui vaadata tehtava töö hulka
ehk täidetavate lausete hulka, siis näeme, et kui esimeses näites
valib kasutaja variandi 1, siis rohkem muutuja N väärtust ei kontrollita . Teises näites aga toimub kontroll veel ka siis, kui
esimese variandi tegevused on juba täidetud.
Sama funktsionaalsusega programmi võib kirjutada kõigis meie poolt
vaadeldavates keeltes - Pascalis,
C's
ja QBasicus.
SUUNAMISLAUSE
SUUNAMISLAUSE on käsk, millega suunatakse programmi täitmine
suunamislausega defineeritud punkti.
Veel kümmekond aastat tagasi oli suunamislause väga laialdaselt
kasutusel. Programmeerimiskeelte Fortran ja Basic
varasemates versioonides oli see kohati asendamatu. Tänapäeva
keeltesse on see jäänud pigem vanade programmidega ühilduvuse
tagamise mõttes, sest on võimalik kirjutada programme ilma
suunamislauset üldse kasutamata. Siiski on meie poolt vaadeltavates
programmeerimiskeeltes kasutusele võetud nn. 'maskeeritud
suunamislauseid'.
Rääkides suunamislausest, ei saa ma rääkimata jätta, mis asi on
märgend. MÄRGEND on programmeerija poolt defineeritav identifikaator, mis märgib ära ühe lause programmis. Seega
võib programmis iga lause ette kirjutada märgendi. Soovides
programmi tööjärge suunata mingi konkreetse lause täitmise
juurde, tuleb meil kasutada suunamislauset koos soovitud lause ees
oleva märgendiga.
Toon ühe näite, mille stiil ja süntaks pärinevad vanematest Basic-keelsetest programmidest. Suunamislauset alustab võtmesõna
'GOTO':
P r o g r a m m N1.1.B.2
10
print "PROTSENTARVUTUSED"
20
print "[1] Osamäära M leidmine terviku T ja osa O järgi"
30
print "[2] Osa O määramine protsendi M ja terviku T järgi"
40
print "[3] Terviku T määramine protsendi M ja vastav osa O
järgi"
70
input "Palun sisesta vajalik ülesandetüüp : ", N
80
if N 1 then goto 130
90
input "Palun sisesta terviku väärtus : ", T
100
input "Palun sisesta osa väärtus : ", O
110
print using "Osamäär on ###.#%"; O/T*100
120
goto 220
130
if N 2 then goto 180
140
input "Palun sisesta terviku väärtus : ", T
150
input "Palun sisesta protsendi väärtus : ", M
160
print "Osa väärtus on "; T/100*M
170
goto 220
180
if N 3 then goto 220
190
input "Palun sisesta protsendi väärtus : ", M
200
input "Palun sisesta osa väärtus : ", O
210
print "Terviku väärtus on "; O/M*100
220
end
Ma loodan, et Te kujutate ette, kui keeruliseks tegid need
'GOTO'- laused inimestele programmi lugemise ja parandamise.
Maskeeritud suunamislauseteks on vaadeldavates keeltes sellised
laused, mille tulemusena toimub samuti programmi täitmise järjekorra
ümbersuunamine. Harilikult on selleks sihtpunktiks käesolevat
lauset sisaldava juhtimislause algus või sellele juhtimislausele
järgneva lause algus. Nendest suunamislausetest räägime koos
juhtimislausetega, kus neid kasutatakse.
Soovi korral võib vaadata ka näiteid suunamislause kasutamise kohta
keeltes Pascal,
C
ja QBasic.
VALIKULAUSE
VALIKULAUSE on programmi juhtkonstruktsioon, mis võimaldab
vastavalt etteantud loendatavat tüüpi avaldise väärtusele suunata
programmi täitma üht paljudest programmiharudest.
Valikulauset on mõistlik kasutada just sellistes olukordades , kus
etteantud avaldise erinevate väärtuste korral peab programm käituma
erinevalt ja neid erinevaid käitumisevariante on rohkem kui kaks.
Just selline olukord oli meil esimeses näites - kolm võimalikku varianti .
Toome siinkohal ära ka valikulauset kasutavad näited keeltes Pascal
, C
ja QBasic.
ÜLESANDED
Kolmnurki liigitatakse külgede pikkuse järgi erikülgseteks, võrdhaarseteks ja võrdkülgseteks. Kirjutada programm, mis küsib kasutajate käest kolmnurga kolme külje pikkused ja väljastab vastusena kolmnurga liigi. Kindlasti tuleb kontrollida, kas etteantud küljepikkustega kolmnurk saab üldse eksisteerida.
Tüüpiline valikutega matemaatikaülesanne on ruutvõrrandi Ax2+Bx+C=0 lahendamine. Seal sõltub lahendite arv ja nende leidmise viis ruutvõrrandi kordajate A, B ja C väärtustest. Teiseks ülesandeks ongi kirja panna programm ruutvõrrandi lahendamiseks.
STRUKTUURSED ANDMETÜÜBID: JADA, MASSIIV, KIRJE, FAIL.
Sissejuhatus
Käesolevas teemas käsitlen ma andmeobjekte, mis omavad erinevalt
lihttüüpi muutujatest struktuuri. Sellest omadusest
tulenevalt nimetatakse neid objekte struktuurset tüüpi
andmeobjektideks. Nende koostisosadeks võivad olla meile juba
tuttavad lihttüüpi andmeobjektid - täisarv, reaalarv ja sümbol -
ning lisaks saab veel kasutada teisi juba olemasolevaid struktuurseid
tüüpe.
Milleks on meil struktuurseid tüüpe vaja? Asi on nimelt selles, et
praktilised ülesanded tulenevad igapäevasest elust ja meid
ümbritsevad objektid on oma atribuutide ehk omaduste poolest liiga
keerulised selleks, et neid saaks kirjeldada vaid ühe arvuga.
Näiteks inimese kirjeldamiseks peame kasutusele võtma mitmeid
muutujaid - inimese ees- ja perekonnanimi , vanus, sugu, kaal, kasv
jne. Kas ei võiks kasutada programmis selle asemel andmetüüpi
nimega 'Inimene'? Selgub , et see on võimalik ja allpool me selleni jõuamegi.
Jada. Massiiv. Massiivi mõõtmed
Kõige lihtsam struktuursetest andmetüüpidest on jada,
milleks nimetatakse samatüübiliste ühe nime alla koondatud
indekseeritavate muutujate komplekti. Liiga keeruline mõiste?
Räägime selle siis lahti ja alustame seejuures definitsiooni
lõpust.
Mida tähendab muutujate komplekt? See tähendab, et meil on
rohkem kui üks muutuja üksteise kõrval. Näiteks selliselt:
----------------------------------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
----------------------------------------------------------------
Mida tähendab indekseeritavad? See tähendab, et neid saab
eristada üksteisest nende järjekorranumbri ehk indeksi
järgi. Et sellele muutujate komplektile on pandud üks nimi,
siis on see ka ainus võimalus neid jadast üles leida. Ja väga
oluline on ka see, et kõik jada elemendid (üksikud muutujad) on
sama tüüpi.
Jada nimetatakse teinekord ka järjendiks või ühemõõtmeliseks
massiiviks. Kõige kasutatavam jada on sümbolite jada, mida
nimetatakse stringiks ning kasutatakse igasuguste nimetuste ja
teksti hoidmiseks.
Massiiv on jadast üldisem mõiste, kuid olemuselt sama - hulk
samatüübilisi muutujaid, kõigile on pandud üks nimi ja igal muutujal on oma indeks. Kui jada on alati ühemõõtmeline, siis
massiivi mõõtmelisuse ehk dimensiooni piirid on piiratud
vaid konkreetse keele võimalustega.
Selleks, et massiivi mõõtmetest paremini aru saada, võtame
kasutusele väikese analoogia geomeetriaga:
Ühele muutujale vastab geomeetrias punkt, ühemõõtmelisele
massiivile (jadale) vastab sirglõik, kahemõõtmelisele
massiivile (maatriksile) vastab ristkülik ja
kolmemõõtmelisele massiivile risttahukas. Ja nii edasi, kui
keegi teab vastavaid nimetusi.
Massiivi deklareerimine
Massiiv kui muutujate komplekt vajab vastavalt oma suurusele mälu.
Selle jaoks tuleb massiiv alati deklareerida. Keeltes, kus on lubatud
massiivide kasutamine esialgselt deklareerimata, on kasutusel
vaikimisi massiivisuurus, mis ei pruugi Teid kui programmeerijat
rahuldada.
Sõltuvalt arvutist, operatsioonisüsteemist või translaatorist võib
esineda piiranguid massiivi suurusele või kasutadaolevale mälule.
Deklareerides massiivitüüpi muutujaid peab nende piiridega
arvestama.
Massiivi indeksi kõige väiksemat ja kõige suuremat väärtust
nimetatakse vastavalt alumiseks rajaks ja ülemiseks
rajaks.
Massiivi deklareerimine keeles
Pascal
Massiivitüüpi muutuja deklareerimise lause on üks variant üldisest
muutujate deklareerimise lausest, mille süntaks keeles Pascal on
järgmine:
'VAR' .
muutujadeklareerimise_laused
->
';' [] .
muutujadeklareerimise_lause
-> ':' .
muutujate_loetelu
-> [ ',' ] .
tüüp
-> | .
struktuurne_tüüp
-> | | .
massiivitüüp
-> ' ARRAY ' '[' ']' 'OF' .
indeksitüüpide_loetelu
-> >indeksitüüp> [ ',' ]
.
indeksitüüp
-> | 'CHAR' | 'BOOLEAN' .
alamhulgatüüp
-> '..' .
Massiivi indeksite hulk peab olema loetletav, seetõttu ei ole
lubatud kasutada indeksina reaalarvutüüpi konstante . Kuna
sümbolitüübi 'CHAR' ja tõeväärtustüübi 'BOOLEAN' väärtused
on loetletavad, siis on lubatud deklaratsioonid kujul
Kood
: ARRAY[Char] OF INTEGER ;
ja
Olekutabel
: ARRAY[Boolean, Boolean] OF Boolean;
Massiivis 'Kood' on 256 elementi ja kuna täisarv on 2 baidi suurune,
siis massiiv võtab ruumi (256 * 2) baiti . Massiivis 'Olekutabel' on
2 * 2 elementi.
Keeles Pascal võivad olla massiivi radadeks mistahes Teie poolt
valitud ja indeksitüübi väärtuste piiridesse jäävad väärtused.
Järgnevalt veel näiteid õigetest massiivi deklareerimise
lausetest:
Jada
: ARRAY[1..100] OF Real;
Maatriks : ARRAY[0..9, 0..19] OF Boolean;
Malelaud : ARRAY['A'..'H', 1..8] OF Char;
X,
Y, Z : ARRAY[-100..100] OF Integer;
Massiivi deklareerimine keeles C
Massiivitüüpi muutuja deklareerimise lause süntaks keeles C on
järgmine:
muutujadeklareerimise_lause
->
[ ] [ ] ';' .
mäluklass
-> 'auto' | 'extern' | ' register ' | 'static' .
modifikaator
-> ' unsigned ' | 'long' | 'short' .
tüüp
-> | .
struktuurne_tüüp
-> .
muutujate_loetelu
->
[ ] [ ',' ] .
dimensioonid
-> '[' ']' [ ] .
dimensiooni_suurus
-> .
Keeles C on massiividel alumise raja väärtus alati 0. Ülemise raja
väärtus on aga dimensiooni suurusest ühe võrra väiksem. Seetõttu
ei ole massiivi otsene kasutamine keeles C nii mugav kui keeles
Pascal, kuid see ei ole põhimõtteline erinevus ja C-fänne see ei
sega.
Järgnevalt mõned massiivideklaratsioonide näited keeles C, mis on
samaväärsed eespool esitatud näidetega Pascali jaoks:
float
Jada[100];
int
Maatriks[10][20];
char
Malelaud[8][8];
int
X[201], Y[201], Z[201];
Massiivi deklareerimine keeles
Qbasic
Massiivitüüpi muutuja deklareerimise lause süntaks keeles QBasic
on järgmine:
'DIM'
['SHARED'] .
muutujadeklareerimise_laused
->
[',' ] .
muutujadeklareerimise_lause
->
[ '(' ')' ] ['AS' ] .
rajad -> [ 'TO' ] [ ',' ] .
alumine_rada
-> .
ülemine_rada
-> .
Kui alumist rada ei deklareerita, siis on selle vaikimisi väärtus
0.
Võtmesõna 'SHARED' kasutatakse aga siis, kui soovitakse, et
massiivi saavad kasutada ka teised programmiosad (funktsioonid,
protseduurid).
Ja järgnevad jällegi eestpoolt tuttavad deklaratsioonid, seekord siis keeles QBasic:
DIM
Jada(1 TO 100) AS SINGLE
DIM
Maatriks(9, 19) AS INTEGER
DIM
Malelaud(1 TO 8, 1 TO 8) AS STRING * 1
DIM
X(-100 TO 100) AS INTEGER, Y(-100 TO 100) AS INTEGER
DIM
Z(-100 TO 100) AS INTEGER ' ei mahtunud enam eelmisele reale ära :-)
Massiivi kasutamine
Massiive kasutatakse praktiliselt igas programmis. Programm, milles
ei ole ühtegi massiivi, on väga erandlik . Sest tuletage meelde,
isegi string on massiiv! Teise kasutusalana võiks märkida korduvaid
protsesse, milles massiivi kasutatakse andmete hoidmiseks.
Massiivi kasutatakse keeles kui harilikku muutujat, kusjuures
muutujanimele lisatakse indeks, mis peab mahtuma massiivi radade
vahele. Vaatame järgnevalt näidet, kus massiivmuutuja 'Jada'
esimesed kolm liiget summeeritakse kokku.
Pascal
Summa
:= Jada[1] + Jada[2] + Jada[3];
C
Summa
= Jada[0] + Jada[1] + Jada[2];
Qbasic
Summa
= Jada(1) + Jada(2) + Jada(3)
Nii nagu lihtmuutujate, nii ka massiivi elementide väärtused on
enne algväärtustamist määramata. Mõnes programmeerimiskeeles
automaatne algväärtustamine siiski toimub, kuid võtke endale
reegliks, et MASSIIVI ELEMENDID TULEB ENNE MASSIIVI KASUTAMIST
ALGVÄÄRTUSTADA.
Kirje
Reaalses maailmas leidub siiski vähe objekte, mille struktuuri saab
kirjeldada mitme ühetüübilise muutujaga. Seega on massiivid sobilikud sarnaste andmehulkade töötlemisel, kuid üksiku objekti
kirjeldamisel võib vaja minna erinevat tüüpi andmeobjekte.
Sellisel juhul on meil kasutada KIRJE, mis on üht loogilist tervikut iseloomustavate muutujate kogum ning need muutuja võivad olla
erinevat tüüpi. Ühte kirje muutujat nimetatakse väljaks.
Põhimõtteliselt ei ole välja tüübil mitte mingisuguseid
piiranguid.
Kirjete koostamisel tuleb mõelda üldisemast konkreetsema
suunas. Tahtes deklareerida kirjetüüpi nimega 'Isik' ja otsides välja meile vajalikke atribuute, võime me algselt deklareerida
stringitüüpi välja 'Nimi'. See väli võib rahuldada meie
vajadusi, võib ka mitte. Näiteks hakkab meid huvitama, et saaks
eristada isiku ees- ja perekonnanime . Me võime siis välja 'Nimi'
asemele tekitada kaks vastavat välja, aga võime ka muuta välja
omakorda kirjeks, mis sisaldab vajalikke üksikasju. Võimalusi on
palju.
Kirje deklareerimine
Kuna kirje deklareerimine on suhteliselt töömahukam kui teiste
andmetüüpide kirjapanemine, siis harilikult deklareeritakse kirje
uue tüübina ja sellele tüübile pannakse nimi, mida saab edaspidi
muutujate deklareerimisel kasutada. Muidugi ei ole selline teguviis
kohustuslik, kuid siiski soovitatav.
Kirje deklareerimine keeles Pascal
Kirjetüübi deklareerimise süntaks keeles Pascal on järgmine:
'TYPE' '=' ' RECORD ' [';']
'END' .
väljade_loetelu
-> [ ';' ] .
väli
-> ':' .
väljanimede_loetelu
-> [ ',' ] .
Paneme kirja ka sobiliku tüübideklaratsiooni isiku andmete jaoks:
Type
Isik = Record
Eesnimi ,
Perekonnanimi
: String[20];
Vanus
: Integer;
Isikukood : String[11];
End;
Kirje deklareerimine keeles C
Kirjetüübi deklareerimise süntaks keeles C on järgmine:
' struct ' '{' '}' ';' .
väljade_loetelu
-> ';' [ ] .
väli
-> .
muutujate_loetelu
->
[ ] [ ',' ] .
Ja isikuandmete kirje deklaratsioon keeles C:
struct
Isik
char
Eesnimi[20], Perekonnanimi[20];
int
Vanus;
char
Isikukood[11];
Kirje deklareerimine keeles Qbasic
Kirjetüübi deklareerimise süntaks keeles C on järgmine:
'TYPE' 'END' 'TYPE' .
väljade_loetelu
-> [ ] .
väli
-> 'AS' .
Ja isikuandmete kirje deklaratsioon keeles Qbasic:
TYPE
Isik
Eesnimi
AS STRING * 20
Perekonnanimi
AS STRING * 20
Vanus
AS INTEGER
Isikukood
AS STRING * 11
END
TYPE
Kirje kasutamine
Deklareeritud kirjetüübi kasutamiseks tuleb deklareerida muutuja,
mille tüübiks on kirjetüüp. Kuna massiivi deklareerimisel on
lubatud elemendi tüübina kasutada igasugust tüüpi, siis võib
moodustada ka kirjete massiive, mida nimetame tabeliks . Paneme
kirja muutujate deklaratsioonid vastavates keeltes:
Pascal
Var
Patsient : Isik;
Patsiendid : ARRAY[1..1000] OF Isik;
C
struct
Isik Patsient;
struct
Isik Patsiendid[1000];
Qbasic
Patsient
AS Isik
DIM
Patsiendid(1000) AS Isik
Kirjemuutuja kasutamisel võib kirjet vaadelda kui üht terviklikku muutujat ja selliste muutujate vahel on lubatud omistamise
operatsioon. Kui on vajadus kasutada üht välja kirjest, siis kõigi
kolme keele süntaks langeb selle koha peal kokku:
'.' .
Tühikuid identifikaatorite ja punkti vahele jätta ei tohi. Kirje
kasutamist illustreerib järgmine näide:
if
Patsiendid[x].Vanus > 50 then
Patsient
:= Patsiendid[x];
Fail
Failiks nimetatakse samatüübiliste komponentide jada,
kusjuures erinevalt ühemõõtmelisest massiivist ei ole komponentide
arv jadas kindlaks määratud ja võib olla kuitahes suur. Faili
komponendiks võib olla mistahes tüüpi andmeobjekt. Kui failis ei ole ühtegi komponenti, on meil tegemist tühja failiga.
Failil on kindlasti olemas nimi. Failiga saab teostada järgmisi
elementaaroperatsioone: faili avamine ja sulgemine , komponendi
lugemine ja kirjutamine. Failist komponendi kustutamise operatsiooni
üldjuhul ei ole. Mõningates keeltes leidub funktsioon vajaliku
järjenumbriga komponendi leidmiseks failist. Failide omapära
seisneb selles, et neid tuleb käsitleda komponenthaaval. Faili avamise järgselt on aktiivseks esimene komponent , selle lugemise
järel teine jne. Ka kirjutamise puhul liigutakse automaatselt
järgmise komponendi alguskohale. Magnetofonilindi kasutamine on
faili kasutamisega sarnane tegevus - saab kuulata (ehk lugeda) ja
lindistada (ehk kirjutada), kustutamine on tõlgendatav lihtsalt
vaikuse kirjutamisena lindile.
Loetavat faili võib alati käsitleda sisendvoona
ja kirjutatavat faili väljundvoona
ning see seletab ka faili käsitlemise järjestikulist olemust.
Faili deklareerimine
Failide deklareerimisel luuakse sobivat tüüpi failimuutuja, mis on
oma olemuselt kirje ja võib kanda endas informatsiooni faili nime,
käsitlemise staatuse ja viimati loetud komponendi kohta.
Failide deklareerimise ja avamise süntaks vastavates keeltes on
järgmine:
Pascal
Süntaks:
'TYPE' '=' 'FILE' 'OF' ';' .
'VAR' ':' ';' .
'Assign'
'(' ',' ')' ';' .
Lugemiseks avamine toimub järgmise käsuga (operatsiooni õnnestumise eelduseks on faili olemasolu):
' Reset '
'(' ')' ';' .
Kirjutamiseks avamine toimub järgmise käsuga:
'Rewrite'
'(' ')' ';' .
Näide:
Type
Tekstifail = File Of Char;
Var
Sisendfail : Tekstifail;
...
Assign(Sisendfail,
'LOEMIND.TXT');
Reset(Sisendfail);
C
Süntaks:
'FILE' ';' .
'=' 'fopen' '(' ',' ')' ';'.
viitmuutuja_nimi
-> '*' .
moodus -> '"' 'r' ['+'] '"' | '"' 'w' ['+'] '"' | '"'
'a' ['+'] '"'.
Näide:
FILE
*Sisendfail;
Sisendfail
= fopen("LOEMIND.TXT", "r");
Qbasic
Süntaks:
' OPEN ' ['FOR' ] 'AS' ['#'] .
moodus
-> 'APPEND' | ' BINARY ' | 'INPUT' | 'OUTPUT' | 'RANDOM' .
failinumber
-> .
Näide:
OPEN
"LOEMIND.TXT" FOR INPUT AS #1
Faili kasutamine
Pärast faili avamist saab faili lugeda ja kirjutada vastavalt
sellele, missuguste parameetritega fail avati. Pärast töö
lõpetamist tuleb fail sulgeda. Kui seda mitte teha, siis ei pruugi
Teie poolt kirjutatud andmed faili jõuda. Failide kasutamise kõigi
võimalustega tutvumine ei mahu kahjuks selle kursuse raamidesse ja
seda tuleb igalühel õppida läbi oma kogemuste.
Toon järgnevalt mõned näited faili kasutamise kohta.
Pascal
Var
Rida
: String[80];
SF,
VF : Text;
begin
Assign(SF,
'Input.txt');
Assign(VF,
'Output.txt');
Reset(SF);
Rewrite(VF);
ReadLn(SF,
Rida);
WriteLn(VF,
Rida);
Close (VF);
Close(SF);
end.
C
#include
main()
char
Rida[80];
FILE
*SF, *VF;
SF
= fopen("Input.txt","r");
VF
= fopen("Output.txt","w");
fgets(Rida,
80, SF);
fprintf(VF,
"%s", Rida);
fclose(VF);
fclose(SF);
Qbasic
DIM
Rida AS STRING * 80
OPEN
"Input.txt" FOR INPUT AS #1
OPEN
"Output.txt" FOR OUTPUT AS #2
LINE
INPUT #1, Rida$
PRINT
#2, Rida$
CLOSE ' sulgeb kõik avatud failid
ÜLESANDED
1. Jada liikmete järjestamine
Tuletame meelde teise teema teist ülesannet. Seal oli meil vaja
järjestada 5 väärtust muutujates A - E. Võtame viis väärtust
(9, 3, 4, 7, 1) ja asetame need jadamuutujasse M, mis on defineeritud
järgneval moel:
Var
M : ARRAY[1..5] OF Integer;
Kirjutage programm, mis omistamislausete abil teostab selle jada
järjestamise.
2. Kooliõpilase andmekirje
koostamine
Kujutage ette, et Teil on vaja koostada andmebaas kooliõpilaste
andmetest. Teil on vaja deklareerida õpilase andmeid
kirjeldava kirje struktuur, kasutades üht Teie poolt valitud keelt.
3. Kolmnurga pindala leidmine
Et kogemused tulevad läbi harjutamise, siis kirjutame ka ühe lihtsa
programmi. Ülesandeks on leida etteantud kolmnurga pindala.
Kolmnurgast saate Te teada kolme külje pikkused, need tuleb lasta
kasutajal sisestada. Ärge unustage kontrollimast, kas sisestatud
küljepikkused saavad kuuluda kolmnurgale!
MÄÄRATUD KORDUS. EELKONTROLLIGA KORDUS. JÄRELKONTROLLIGA KORDUS.
SISSEJUHATUS
Nüüd, kus me oleme tutvunud peaaegu kõigi programmeerimise
põhilisemate ehituskividega - muutuja, avaldise, sisend-, väljund-
ja tingimuslausega -, jääb meil minimaalsest vajalikust komplektist
puudu vaid KORDUSLAUSE. Kui osatakse neid põhilisi ehituskive
kasutada, võib kirjutada programme igasuguste ülesannete
lahendamiseks. Kõik ülejäänud 'värvid ja viled' on keeltesse
sisse toodud programmeerijate töö lihtsustamiseks ja tööviljakuse
tõstmiseks.
Juba KORDUSLAUSE nimetus ise selgitab tema otstarvet - selle lause
abil saab lasta arvutil täita mingisugust hulka lauseid mitu korda
järjest. Millises olukorras läheb sellist tegevuste kordamist vaja?
Toome näiteks eelmisest teemast tuttava jada ja ülesande, kus me
ühe jadaliikme M[i] korral peame tagama, et tema väärtus ei oleks
negatiivne:
KUI
M[i] M[i]
:= 0
KUILÕPP
Laiendades seda nõudmist kogu jada peale, peaksime seda tegevust
kordama iga jadaliikmega. Siin me saamegi kasutada korduslauset:
i
:= 1 -- alustame jada esimesest liikmest
KORDUS
SENIKUI i .
algväärtus -> .
lõppväärtus -> .
samm -> .
tegevus -> .
Selle lause võtmesõnana kasutatakse põhiliselt stringi "FOR",
mistõttu võidakse määratud kordusest rääkida ka kui
for-lausest.
EELKONTROLLIGA KORDUS
EELKONTROLLIGA KORDUS on korduslause, mille korral täidetakse
etteantud tegevust seni, kui esitatud tingimus on täidetud.
Tingimust kontrollitakse ENNE tegevuse täitmist. Lause täitmise
algoritm on järgmine:
A)
Kui esitatud tingimus pole tõene, siis lõpetatakse korduslause
täitmine
ja juhtimine läheb järgneva lause kätte.
B)
Täidetakse korduslause sisuks olevad laused.
C)
Pöördutakse sammu A) juurde tagasi.
Graafiliselt kujutatuna võiks eelkontrolliga kordus välja näha
järgmine:
V
------------------ jah +---------+
-------> | Tegevus |
------------------ +---------+
| ^ |
|
ei | |
| +-----------------+
v
Selle korduslause eripäraks on, et tegevust võidakse teha 0 ...
N korda, kusjuures väärtus N on sõltuvuses esitatud
tingimusest ja ei ole ette määratud.
Üldistatud süntaks eelkontrolliga korduse jaoks on järgmine:
'KORDUS
SENIKUI'
'KORDUSELÕPP'
.
tingimus
-> .
JÄRELKONTROLLIGA KORDUS
JÄRELKONTROLLIGA KORDUS on korduslause, mille korral täidetakse
etteantud tegevust vastavalt PÄRAST tegevust esitatud tingimusele.
Lause täitmise algoritm on järgmine:
A)
Täidetakse korduslause sisuks olevad laused.
B)
Kui esitatud tingimus pole tõene, siis lõpetatakse korduslause
täitmine
ja juhtimine läheb järgneva lause kätte.
C)
Pöördutakse sammu A) juurde tagasi.
Graafiliselt kujutatuna võiks järelkontrolliga kordus välja näha
järgmine:
| -----+
----------
v
Selle korduslause eripäraks on, et tegevust võidakse teha 1 ...
N korda, kusjuures väärtus N on sõltuvuses esitatud
tingimusest ja ei ole ette määratud. Põhiline erinevus eel- ja
järelkontrolliga korduse vahel on see, et eelkontrolliga korduse
puhul võib jääda tegevus üldse tegemata, aga järelkontrolliga
korduse puhul tehakse seda vähemalt üks kord.
Üldistatud süntaks järelkontrolliga korduse jaoks on järgmine:
'KORDUS'
'KUNI' .
tingimus
-> .
Tingimuse kasutamine järelkontrolliga korduslauses võib jääda
pisut segaseks ning sellel on ka põhjus. Ma ei saa konkreetsemalt rääkida, sest erinevad keeled kasutavad seda tingimust erinevalt.
Näiteks keeles Pascal lõpetatakse tegevus siis, kui tingimus on
tõene ning vastupidisel juhul jätkatakse tegevust. Keeles C
toimitakse vastupidiselt. Kuid see ei ole põhimõtteline erinevus.
Korduslaused keeles Pascal
Määratud korduse süntaks:
'FOR' ':=' ( 'TO' | 'DOWNTO' ) 'DO'
Eelkontrolliga korduse süntaks:
' WHILE ' 'DO'
Järelkontrolliga korduse süntaks:
' REPEAT '
' UNTIL ' .
tegevus
-> [ ] | 'BEGIN' [ ][ ';' ]
'END'.
lausete
jada -> [ ';' ].
Korduslaused keeles C
Määratud korduse süntaks:
'for'
'(' []';'[] ';' []
')'
initsialiseerimine
-> [ ',' | '{' '}' .
Korduslaused keeles Qbasic
Määratud korduse süntaks:
'FOR' ':=' ( 'TO' | 'DOWNTO' ) 'DO'
Eelkontrolliga korduse süntaks:
'DO'
( 'WHILE' | 'UNTIL' )
' LOOP '
|
'WHILE'
' WEND '
.
Järelkontrolliga korduse süntaks:
'DO'
'LOOP'
( 'WHILE' | 'UNTIL' ) .
KORDUSLAUSETE KASUTAMINE
Kõige parem on korduslausete kasutamist selgitada näidete kaudu.
Võtame ühe lihtsa ülesande ja kirjutame vastava programmi.
Näide 1.
Ü l e s a n n e: Koostada programm, mis leiab sisestatud arvujada kõige suurema väärtuse.
Lahenduse panen ma kirja keeles Pascal: <
Program
Jada_Suurim_Vaartus;
Const MaxN = 100;
Var
Jada
: array [1..MaxN] of Integer;<<
i : Integer;
Begin
Writeln('See
programm leiab arvujada suurima väärtuse.')
Write('Palun
sisesta jada pikkus : '); Read(N);<
begin
Write('Palun
sisesta jada ',i,'. elemendi väärtus : ');
Read(Jada[i]);
end;
Write('Tänan! Otsin suurimat väärtust ...');
Max
:= Jada[1];<
if
Jada[i] >
Max
:= Jada[i];
Writeln;
Writeln('Jada
suurim väärtus on ', Max);
End.<
Nagu näha, saab iga jadaliiget töödelda samade lausetega.
Korduslause abiga tagab programmeerija massiivi indeksi muutumise
nii, et järjest vaadeldakse kõiki jadaliikmeid. Tulemuste
hoidmiseks kasutatakse harilikke muutujaid, antud juhul muutujat
'Max'.
Näide 2.
Ü l e s a n n e: Kirjutada programm, mis teisendab etteantud
tekstifailis olevad pseudo -täpitähed ASCII 437 (või ANSI)
kooditabeli vastavateks täpitähtedeks. Pseudotäpitähed on o~, a",
o", u", O~, A", O", U".
Lahenduse idee seisneb tekstifailist saabuva sümbolitevoo saatmisel
läbi kahekohalise puhvri. Umbes nii:
sümbol +---------+-------+ sümbol
Sisendfail
--------> | Esimene | Teine | --------> Väljundfail
+---------+-------+
Puhver
Kui esimesel kohal on märk '"' või '~' ja teisel kohal 'a',
'o' või 'u', siis asendan need kaks märki vastava täpitähe koodiga .
Selle programmi kirjutan keeles C.
/*
P r o g r a m m i a l g u s */
#include
#define
MaxUmlaud 6
#define
MaxTilde 2
main()
char
asc_nimi[40], txt_nimi[40];
FILE
*infile, *outfile;
char
esimene, teine; /* neid kasutame kui kahekohalist puhvrit */
/*
Järgnevatest kommentaaridest võib välja jätta vajaliku osa. */
/*
Näiteks '\204' on tähe 'ä' kood _kaheksandsüsteemis_ ;) */<;
/*
ANSI '\344','\366','\374','\304','\326','\334'}; */ <;
/*
ANSI '\365','\325'}; */
int
i;
printf("TXT2ASC Demo \n\n");
for
(i=0; i %c \n", umlaud[0][i], umlaud[1][i]);
for
(i=0; i M[j] SIIS -- Kui esimene liige on suurem kui teine,
C := M[j] -- siis vahetame need liikmed.
M[j]
:= M[i]
M[i]
:= C
KUILÕPP
KORDUSELÕPP
KORDUSELÕPP
Teie ülesandeks jääb kirjutada programm Teie poolt valitud keeles,
mis järjestab sisestatud arvud kasvavasse järjekorda, kasutades
selleks mullimeetodit. Peale järjestamist tuleb arvud esitada
ekraanile.
Arvude sisestamisel küsige kõigepealt arvude hulk, sest siis Te
teate, mitu korda tuleb sisestamislauset välja kutsuda.
--------------------------
Minimaalseima väärtuse leidmine maatriksist
Te kindlasti mäletate, et maatriks on kahemõõtmeline arvumassiiv.
Teie ülesandeks on kirjutada programm, mis sisestab massiivi
elementide väärtused ja seejärel leiab kõige väiksem väärtuse
massiivis.
Abiks on ehk selline tähelepanek, et maatriks on jadade jada ;)
Suurima summaga rea leidmine maatriksist
Kui maatriks on juba sisse loetud, siis võiks ju temaga midagi veel
teha. Näiteks võiks leida suurima summaga rea. Ekraanile väljastage
summa väärtus ja rea number.
VIITMUUTUJA. ARVUTI MÄLU PAINDLIK KASUTAMINE
SISSEJUHATUS
Selle teema raames tutvustan ma Teile üht omapärast andmeobjekti -
VIITMUUTUJAT. Selleks, et järgnevast jutust hästi aru saada, tuleb
meelda tuletada teises teemas käsitletud jutt MÄLU kohta.
Kõik senivaadeldud andmeobjektid on olnud STAATILISED. Staatiline
andmeobjekt tuleb programmis kirjeldada: talle peab andma nime
ja tüübi. Programmi täitmise ajaks eraldatakse muutuja
väärtuse hoidmiseks teatud osa arvuti mälust ja seotakse muutuja
sellega mäluaadressi abil. Muutuja tüüp määrab väärtuse
esitamiseks vajaliku mäluhulga ning muutujaga teostatavad
operatsioonid. Muutujale viitamiseks kasutatakse tema nime.
Programmeerijal pole võimalust muuta nime ja mäluaadressi vahelist
seost.
VIITMUUTUJA OLEMUS
Keeltes Pascal ja C on olemas võimalus tekitada andmeobjekte ka
alles programmi täitmise käigus - dünaamiliselt. DÜNAAMILISE
muutuja seostamiseks mäluaadressiga kasutatakse viitmuutujat.
VIITMUUTUJA ehk lühemalt öeldes VIIT on andmeobjekt, millesse
saab salvestada mingi teise andmeobjekti mäluaadressi.
Viitmuutuja kirjeldamisel peab määrama ka selle poolt viidatava
andmeobjekti tüübi. Lisaks dünaamilistele muutujatele võib viit
viidata ka harilike muutujate peale.
Viitmuutuja väärtus võib olla üks kolmest võimalikust:
1)
viit on väärtustamata ja väärtus on juhuslik suurus;
2)
väärtuseks on omistatud mäluaadress;
3) väärtuseks on
omistatud "TÜHI VÄÄRTUS".
Vaatame järgnevat tabelit:
Aadress Muutujanimi Tüüp Väärtus
+-----------------------------------------+
| 0001 A Täisarv 5 |
| 0003 B Täisarv 2 |
| 0005 VA Viit TÜHI |
| 0009 VB Viit 0003 |
| ... |
+-----------------------------------------+
Meil on defineeritud kaks täisarvulist muutujat ja kaks
viitmuutujat. Esimesele viidale VA on omistatud väärtuseks "TÜHI",
mis tähendab, et see viit ei viita mitte millelegi. Harilikult on selliseks "TÜHJAKS" väärtuseks 0, kuid see sõltub
konkreetsest keelest. Teisel viitmuutujal VB on väärtuseks 0003,
mis on samal ajal ka muutuja B aadressiks. Sellisel juhul võib
öelda, et viit VB viitab muutujale B.
Kujutame kirjeldatud muutujaid joonisega:
+-----+
| A |
+-----+
| B |
P
:= @B;
Writeln('Nendest
arvudest väiksem on ',P^);
end.
Nagu näitest näha võis, kasutatakse aadressi järgi viitamiseks
viitmuutujat, millele järgneb vahetult märk '^'. Selline programm
on muidugi teostatav ka lihtsamalt, kuid see demonstreerib viida
kasutamise võimalusi. Dünaamiliste muutujate kasutamine on aga ilma
viitmuutujata raske kui mitte lausa võimatu. Aga sellest tuleb juttu
allpool.
Viitmuutuja kasutamine keeles C
Viitmuutujate tähistamine keeles C on mõnevõrra segadusttekitav,
sest selleks kasutatakse märki '*', mis langeb kokku korrutamise
operaatoriga. Seega on oluline jälgida, et ei tekiks kahemõttelisust
ja sinna, kus selline oht on olemas, tuleb panna sulud.
Viitmuutuja deklareerimine käib järgmiselt:
int
*lp; /* lp on viit täisarvu peale */
Tühja väärtuse määramine viidale toimub kas arvu 0 või
eeldefineeritud konstandi NULL (mis harilikult on pikk täisarv 0 ehk
(long int)(0)) omistamisega:
lp
= NULL;
Olemasoleva muutuja X aadressi omistamine viidale toimub operaatori
'&' abil:
lp
= &X;
Ja kirjutame eespool esitatud programmi keele C:
/*
N8_1_C */
#include
main()
int
A, B, *P;
P
= &A; /* viit paigaldatakse muutuja A peale
*/
printf("Palun
sisesta arv : ");
scanf("%d",
&A); /* ka sisestamise funktsioon kasutab aadressi! */
printf("Tore,
sain kätte arvu %d\n", *P); /* kasutame viita */
printf("Palun
sisesta teine arv : ");
scanf("%d",
&B);
if
(*P > B) /* ehk kui A >
B */
P
= &B; /* paigaldame viida muutuja B peale
*/
printf("Nendest
arvudest väiksem on %d\n", *P);
return
0;
/*
lõpp */
MÄLU PAINDLIK KASUTAMINE
Ei ole harvad sellised ülesanded, mida saab täita mitmes osas ja
millest iga osa vajab suurt hulka mälu. Kui lahendada ülesanne
staatiliste muutujatega, see tähendab selliste muutujatega, mille
jaoks reserveeriti mälu programmi töö alguses ja nad eksisteerivad
kuni programmi lõppemiseni, siis võib meil mälust puudus tulla.
Üks võimalik lahendusvariant on selline, et vajaminevad muutujad
luuakse vahetult enne seda, kui neid kasutama hakatakse ja siis, kui
neid enam vaja ei ole, kaotatakse nad ära. Selliseid muutujaid
nimetataksegi DÜNAAMILISTEKS MUUTUJATEKS.
Mälu hõivamine
Dünaamilise muutuja tekitamine algab muutuja jaoks mälu küsimisega.
Mälu võib küsida, andes ette konkreetse arvu (baitides) või
andmetüübi. Kui küsitud hulk vaba mälu on veel olemas, siis
hõivatakse see ja vastav aadress omistatakse viitmuutujale.
Mälu hõivamiseks on programmeerimiskeeles spetsiaalsed
funktsioonid. Kindlasti eksisteerib konkreetse suurusega mäluala
hõivamise funktsioon.
Keeles Pascal on selleks protseduur GETMEM, mille deklaratsioon on
järgmine:
procedure
GetMem(var P: Pointer; Suurus: Word);
Kasutades seda protseduuri võib hõivata mälu 'Suurus' arv baite ja
aadressi omistada viitmuutujale P. Tüüp 'Pointer' on puhas
viidatüüp.
Keeles C on selleks funktsioon MALLOC, mille deklaratsioon on
järgmine:
void
*malloc( size_t suurus );
Funktsioon tagastab puhta viidatüüpi (void *) väärtuse 'suurus'
arv baite sisaldavale mäluosale.
Teine liik mälu hõivamise funktsioone on seotud konkreetse
andmetüübiga. Keeles Pascal on selleks protseduur New:
procedure
New(var P: Pointer);
See protseduur uurib järele viida P tegeliku tüübi ja eraldab mälu
vastavalt tüübi suurusele. Näiteks täisarvu viida tüübi korral
eraldatakse mälu ühe täisarvu hoidmiseks.
Keeles C "tüübiga" mäluhõivamist ei ole, see on lisatud
keele C++ süntaksile.
Võib tekkida küsimus, et "mis saab siis, kui vaba mälu ei
ole?". Programmi käitumine sellises situatsioonis sõltub
keelest ja translaatori versioonist. Pascali puhul võib ette tulla
nii väärtuse 'Nil' tagastamist kui ka veateadet. Keeles C on
üldiselt tavaks tagastada tühi väärtus, mida saab sellisel juhul
kontrollida ja valida vastav käitumine.
Mälu vabastamine
Kui dünaamilised muutujad on oma töö teinud, siis on ilus nad ära
kaotada ja vabastada nende jaoks hõivatud mälu. Selle jaoks on
olemas vastavad protseduurid. Keeles Pascal on nendeks:
procedure
FreeMem(var P: Pointer; Suurus: Word);
procedure
Dispose(var P: Pointer );
FreeMem vabastab GetMem'iga hõivatud mälu, kusjuures arv 'Suurus'
peab olema sama, ja Dispose vabastab protseduuriga New hõivatud
mälu.
Keeles C on mälu vabastamiseks funktsioon FREE:
void
free(void *viit);
Vaatame siinkohal samasisulisi näiteprogramme nii Pascalis kui ka
C-s, kus toimub mälu hõivamine ja vabastamine.
Ü l e s a n n e: Sisestada üks rida teksti ja leida reas
olevate tühikute arv.
Program
N8_2_P;
Var
S : ^String;
i,
n : Integer;
begin
Writeln('Palun
sisesta üks rida teksti:');
GetMem(S,
81);
Readln(S^);
n
:= 0;
For
i := 1 to Length (S^)
If
S^[i] = ' '
n
:= n + 1;
FreeMem(S,
81);
Writeln('Selles
reas on ', n, ' tühikut.');
end.
/*
N8_2_C */
#include
#include
#include
main()
char
*S; /* viitmuutuja */
unsigned
i, n; /* märgita täisarvud */
printf("Palun
sisesta üks rida teksti:\n");
S
= malloc(81); /* küsime 81 baiti mälu */
if(S
== NULL) /* kontrollime, kas mälu saime */
printf("Nii
palju vaba mälu ei ole!\n");
else <'
parameetrite_nimed
-> [ ',' ] .
parameetrite_deklaratsioonid
->
[ ] .
parameetri_deklaratsioon
-> ';' .
Näide:
int
Max( a, b )
int
a, b;
if
( a > b)
return
a;
else
return
b;
FUNKTSIOONI VÄLJAKUTSUMISE SÜNTAKS:
'(' [ ] ')' .
Näide:
M
= Max(i, j);
Qbasic
PROTSEDUURI DEKLAREERIMISE SÜNTAKS:
'SUB' [ '(' ')' ]
'END'
'SUB' .
formaalsed_parameetrid
->
[ '(' ')' ] ['AS' ] [',' ]
.
Näide:
SUB
Vaheta ( a AS INTEGER, b AS INTEGER )
c
= a
a
= b
b
= c
END
SUB
FUNKTSIOONI DEKLAREERIMISE SÜNTAKS:
'FUNCTION' [ '(' ')' ]
[ ]
[ ]
'END'
'FUNCTION' .
Näide:
FUNCTION
Max ( a AS INTEGER, b AS INTEGER )
IF
a > b THEN
Max
= a
ELSE
Max
= b
ENDIF
END
FUNCTION
PARAMEETER
Enne, kui hakkan selgitama mõningaid mõisteid, esitan ma ühe
keeles Pascal kirjutatud näiteprogrammi, kus on kasutatud nii
protseduure kui ka funktsioone koos parameetritega ja ilma.
Ü l e s a n n e:
On antud N (64;)
putchar(!d+++33^
l&1);}
See
programm tahab töötamiseks kahte arvulist parameetrit, näiteks:
>
world 58 26
Mida
see programm küll teha võiks? ;-)
Korraliku
vormistamise eesmärgiks on keele enda vahenditega kirjutada
hästi loetav programm. Kui on vaja selgitada kasutatava algoritmi sisu-
lisi
nüansse, siis selleks kasutatakse kommentaare. Paljusid lihtsaid
algoritme
võib protseduuriks või funktsiooniks vormida ilma sõnagi
kommentaariks
lisamata.<
Type
Arvujada
= Array[1..100] of Integer;
Function
ArvujadaSumma
(
Jada : Arvujada;
LiikmeteArv
: Integer )
:
LongInt;
Var
Summa : Longint;
Indeks
: Integer;
Begin
If
LiikmeteArv > 100 Then
LiikmeteArv
= 100;
Summa
:= 0;
For
Indeks := 1 To LiikmeteArv Do
Summa
:= Summa + Jada[Indeks];
ArvujadaSumma
:= Summa;
End;
Mis
teeb ühe programmi hästi loetavaks ? Selle kohta võib leida mitmeid
soovitusi:
1)
Kirjutage programm nii lihtsalt ja arusaadavalt kui võimalik,
hoiduge
kavalatest
nippidest. Seda nimetatakse KISS -printsiibiks (inglise kee-
lest 'Keep It Simple , Stupid').
2)
Kasutage iseennast selgitavaid identifikaatoreid.
3)
Struktrueerige oma programmi, kasutades tühje ridu, taandeid ja tabu -
laatoreid.
4)
Kasutage mõistlikult kommentaare.
Igal
programmeerijal kujuneb aja jooksul välja oma 'käekiri', millest
suur
osa kajastub programmi vormistamise harjumustes - programmeerija
STIILIS.
Hea vormistus on hea stiili tunnuseks.
Kommentaaride
kasutamisest teen ma juttu järgmises teemas, seekord vaat-
leme
lähemalt identifikaatoreid ja taanete kasutamist.
2.
Identifikaatorite süstematiseerimine.
Iga
identifikaatori kohustuslikuks osaks peaks olema string, mis viitab
identifikaatori
SISULISELE tähendusele - see on ennastselgitavuse alu-
seks.
Kui meil on vaja valida nimi muutujale, milles hoitakse väärtust
pikkuse
kohta, siis peaks valima mõne järgmistest nimedest : Pikkus,
Length,
Pikk, Len, P, L. Esimesed on paremad, viimaseid võib kasutada
mõningate
mööndustega. Võib kasutada ka võõrkeelseid nimetusi ja nendest
tuletatud lühendeid. On hea, kui sisuliselt erinevate muutujate nimed ei
ole
väga sarnased.
Suurte
programmide korral, kus kasutuses on sadu ja tuhandeid identifi-
kaatoreid,
tahetakse neid lisaks sisule süstematiseerida ka tegevuspiir-
konna
ja tüübi järgi.
Näiteks
tegevuspiirkonna määratlemiseks kasutatakse eesliiteid 'l', 'g'
ja
'a' vastavalt sellele, kas tegemist on lokaalse või globaalse muutu-
jaga
või parameetriga:
'lTabel'
- lokaalne muutuja;
'gTabel'
- globaalne muutuja;
'aTabel'
- parameeter.
Defineeritud
konstantide eesliitena on kasutatav täht 'k' või 'c':
'cMaxValue'
- konstant.
Kui
on tahtmine näidata muutuja nimega ka muutuja tüüpi, siis võib
keh-
testada
vastava 'kooditabeli'. Näiteks Microsoft järgib oma toodetes
'Ungari
notatsiooni', mille koostas firma programmeerija Charles Simonyi
(kes
on rahvuselt ungarlane). Mõned näited:
nPikkus
: Integer;
sNimi : String;
wMask : Word;
Pole
tähtis, kuidas Teie süstematiseerite oma identifikaatoreid, tähtis
on
vaid see, et kogu programmi ulatuses on tähistus ühesugune.
3.
Taanete kasutamine.
Kui
vaadelda programmi üldises mõttes, siis see koosneb käskude
jadast,
milles
mõned käsud (nagu valikud ja kordused) võivad sisaldada omakorda
käsujadasid.
Programmi lugedes tunneme me harilikult huvi selliste suu-
remate
struktuuride algus- ja lõpp-punktide vastu. Kujutage nüüd endale
ette
sadu ridasid programmi, mille kõik read algavad esimesest positsi-
oonist.
See on siis midagi sellist:<
For
i := 1 To N-1 Do
For
j := i To N Do
If
A[i]
begin
V
:= A[i];
A[i]
:= A[j];
A[j]
:= V
end;
Sellisest
ühtlasest jadast on väga raske leida mingisuguse struktuuri
algust
ja lõppu. Kui nüüd sellise programmi kompileerimisel ilmneb, et
kuskil
on üks 'end' puudu, siis ei jäägi muud üle, kui asuda kõiki võt-
mesõnu
'begin' ja 'end' omavahel 'paari panema '. Ja selliseks struktuuri
esiletõstmiseks
kasutatakse TAANDEID.
Üldine
reegel seisneb selles, et STRUKTUURI SISSE JÄÄVATE LAUSETE ALGU-
SED
NIHUTATAKSE VÄHEMALT ÜHE KOHA VÕRRA PAREMALE. Tavaliselt on nihke
suuruseks
2 kuni 4 kohta.
Vahel tekkib küsimus, et kuhu kirjutada need võtmesõnad 'begin' ja
'end'?
See on mõningas mõttes maitse asi ja siin on kolm võimalust -
mitte
nihutada, nihutada poolikult ja nihutada täielikult. Vaatame neid
variante:<
For
i := 1 To N-1 Do
For
j := i To N Do
If
A[i] begin
V
:= A[i];
A[i]
:= A[j];
A[j]
:= V
end;<
For
i := 1 To N-1 Do
For
j := i To N Do
If
A[i] begin
V
:= A[i];
A[i]
:= A[j];
A[j]
:= V
end;<
For
i := 1 To N-1 Do
For
j := i To N Do
If
A[i] begin
V
:= A[i];
A[i]
:= A[j];
A[j]
:= V
end;
Märksa
tähtsam on see, et üksteises sisalduvad struktuurid on selgelt
eristatud :
esimene määratud kordus sisaldab teist määratud kordust ja
see
omakorda valikuliselt täidetavat käsujada.
Siinkohal
tahaksin soovitada ühte programmi kirjutamise võtet, mis tagab
selle,
et ükski 'end' ära ei unune. Nimelt, alati, kui kirjutate
'begin',
kirjutage kohe järgmisele reale temaga paaris olev 'end' ja
alles
seejärel kirjutage nende kahe vahele vajaminevad laused. Pisiasi,
kuid
oluline.
PROGRAMMI
DOKUMENTEERIMINE. KOMMENTAARID
PROGRAMMI
PROJEKTEERIMINE JA TESTIMINE
1.
Kellele ja milleks on vaja dokumentatsiooni?
Iga
programmiga, mis on mõeldud laiemaks levitamiseks, peab kaasnema
dokumentatsioon selle programmi kohta. Veel mõned aastad tagasi oli
loomulik,
et see dokumentatsioon oli trükitud kujul. Tänapäeval on
paljud
programmipaketid varustatud ka elektroonilisel kujul oleva
dokumentatsiooniga
- niinimetatud 'abifailidega'.
Dokumentatsioon
jaotub mitmesse ossa sõltuvalt sellest, kellele ja
milleks
see on kokku pandud:
1)
Kasutajajuhendid. Siia hulka kuuluvad materjalid, mis tutvustavad
programmi
omadusi ja aitavad läbi viia väikese proovi ning põhjalikumad
kasutajatele
orienteeritud käsiraamatud, niinimetatud 'manuaalid'.
Kasutajajuhendites
on kõike püütud seletada kasutaja vaatevinklist
lähtudes
ja üldiseks eesmärgiks on aidata kaasa programmi efektiivsele
kasutamisele.
2) Administraatori juhendid. Siia kuulub programmi installeerimise
juhend
ja käsiraamatud programmi hooldamiseks. Ühe kasutaja programmidel
on
installeerimine tehtud sageli väga lihtsaks ja see erilist probleemi
ei
tekita, kuid suurte süsteemide tööle panemiseks on tihti vajalik
spetsialisti kohalolek ja siis on vaja kuidagi edasi anda programmi
koostaja
näpunäited - selleks siis ka installeerimise juhend. Programmi
hooldamise
juhendid sisaldavad endas harilikult näpunäiteid mõningate
tegevuste,
nagu näiteks andmete arhiveerimine , läbiviimiseks ja
lihtsamate
veasituatsioonide lahendamiseks.
3)
Programmi tehniline dokumentatsioon. See sisaldab endas kogu projekt-
dokumentatsiooni,
testimiste protokolle ja võimaluse korral ka programmi
lähtetekste.
Need kõik on vajalikud, kui tahetakse olemasolevat program-
mi
parandada või täiendada.
2.
Programmi lähteteksti dokumenteerimine
Eelmises
teemas lubasin, et seekord tuleb juttu kommenteerimisest. Kuna
programmi
lähtetekst on mõeldud ka inimesele lugemiseks, siis vormista-
mise ühe osana tuleb seda ka täiendada ka selgitava tekstiga .
KOMMENTAAR
on programmis selgituse või täpsustusena kasutatav teksti-
lõik,
mis ei mõjuta programmi tööd. Kuigi ei ole kindlaid reegleid selle
kohta,
kuidas kasutada kommentaare, on siingi mõned printsiibid , mida
võiks
järgida:
*
kommenteerida tuleb nii palju kui vajalik ja nii vähe kui võimalik;
*
kommenteerides püüdge ennetada lugeja küsimusi;
*
kirjeldada tuleb põhilisi funktsioone ja tegevusi;
*
andke piisav seletus kasutatavatele muutujatele;
*
ärge kommenteerige niigi arusaadavaid lauseid.
Jätke
endale meelde, et mõistlik kommenteerimine suurendab märgatavalt
programmi
loetavust.
Lisaks
sisulisele kommenteerimisele kasutavad professionaalsed
programmeerijad ka programmi lähteteksti dokumenteerimist, mis tähendab,
et
iga programmimooduli ja alamprogrammi algusesse lisatakse spetsiaal -
selt vormistatud kommentaar, mis sisaldab:
1)
mooduli või funktsiooni täielikku nimetust ;
2)
otstarve lühikest kirjeldust;
3)
sisendandmete kirjeldust;
4)
väljundandmete kirjeldust;
5)
autori(te) nime(sid) ja loomise kuupäeva;
6) muudatuste põhjuseid ja kuupäevi koos muudatuse tegijate nimedega.
Selline
lähenemine võimaldab saada programmi teksti lugedes kirjapandust
parema
ülevaate ning hiljem jälgida arendustööde käiku.
3.
Mis on programmi projekteerimine?
Suurte
programmide loomist on tihti võrreldud maja ehitamisega. Tõsi
küll,
et mõned sellised tähelepanekud ei ole programmeerijatele auks.
Nagu
näiteks üks Murphi seadustest võetu:
"Kui ehitajad ehitaksid maju samamoodi nagu programmeerijad loovad
programme,
siis esimene kohalelennanud rähn hävitaks tsivilisatsiooni".
See
tähendab, et paljud programmid kujutavad endast kaardimajakesi, mis
küll
seisavad püsti, kuid ei pea vastu ühelegi juhuslikule tuulepuhan-
gule.
Selliste programmide tunnuseks on see, et kasutajad peavad käima
mööda
juba pikka aega sissetallatud radu ja hoidku jumal neid selle
eest,
et nad sellelt rajalt kõrvale ei pööraks - halvemal juhul võib
see
lõppeda
totaalse kräshiga. Need on niinimetatud 'mittelollikindlad
programmid'.
Mõni võib mõelda, et 'mis nad siin jamavad, parandagu vead
ära
ja asi korras', aga kui minna neid vigu parandama, siis selgub, et
ei
eksisteeri mitte mingisugust dokumentatsiooni, programmi tekst on
halvasti
vormistatud jne. Parandades sellises programmis ühte viga, võid
suure
tõenäosusega teha mitu uut - lihtsalt puudub ülevaade.
Eelneva
jutu moraaliks on see, et TULEB ÕPPIDA EHITAJATELT. Tänapäeval
ei
ehitata enam niimoodi , et kõigepealt tuuakse kohale koormatäis tel-
liskive
ja hakatakse laduma. Kõigepealt vaadatakse, kuhu ehitada ja
millist
maja tulevane elanik soovib. Seejärel tehakse majale PROJEKT
(see
on juba arhitektide asi, kui nad uut projekti ei joonista vaid
võtavad
kapist mõne vana). Kui kõik funktsionaalsus, kasutatavad mater -
jalid
ja töömahud on läbi mõeldud, alles siis hakatakse kive laduma. Ja
suurem
enamus majadest seisab püsti ja on elanikke täis - ju siis sai
ehitatud
head majad. Seesama jutt käib ka programmide loomise kohta.
Nii
nagu uut tüüpi majade puhul ehitatakse makette ehk väikeseid mude-
leid,
nii luuakse ka keeruliste programmide jaoks kõigepealt mudelid
ning
nende peal 'mängitakse läbi' programmi kasutamine ja üldine funkt-
sionaalsus.
Programmi projektdokumentatsioon koosnebki harilikult mudeli
kirjeldusest,
milles on esitatud kasutatavad andmestruktuurid, funkt-
sioonid ja nende omavahelised suhted, andmete liikumise suund ja ajaline
järjekord,
kasutajaliides ja veel palju muud. Selliste programmi mudeli-
te
loomiseks kasutatakse CASE -vahendeid - programme, mis võimaldavad
projekteerijal
koostada mitmeid spetsiaalseid diagramme ning mis on suu-
telised kontrollima koostatud mudeli korrektsust ja genereerima program-
mi
tooriku, mida siis programmeerija saab oma töös otseselt kasutada.
4.
Putukate ärastamine ja trablite laskmine
4.1
Vead
Inglise
keeles on programmis leiduvate vigade jaoks kasutusel sõna 'bug'
ja
tegevust vigade eemaldamiseks programmist nimetatakse sõnaga
'debugging'.
Et 'bug' tähendab ka putukat, siis sõna 'debugging' võib
tõlkida
ka kui 'putukate eemaldamine'. Ja kui keegi räägib programmi
silumisest,
siis on samuti tegemist vigade otsimise ja parandamisega.
Tõsiseks
probleemiks ei ole tihti mitte vea eemaldamine vaid selle LEID-
MINE.
Seetõttu tutvume kõigepealt tüüpiliste vigadega, mida programmide
koostajad
teevad. Järgnev loetelu on ülevaade situatsioonidest, kus
üldiselt
tehakse 99% vigadest. Kui programmeerija suudab kõiki neid
"putukaid"
vältida, siis töötavad tema programmid stabiilselt ja hästi.
VEAD
ANDMETE KASUTAMISEL
*
Muutuja on jäänud initsialiseerimata. Siinkohal tuleb alati
kaaluda:
kas
muutuja vajab algväärtustamist ja kui vajab, siis kus (programmi
alguses,
tsükli alguses)?
*
Massiivi indeks ületab lubatud piiri.
VEAD
ARVUTAMISEL
*
Muutuja ületäitumine.
*
Avaldise vahetulemuse ületäitumine.
*
Jagamine nulliga.
*
Funktsiooni kasutamine väljaspool määramispiirkonda (ruutjuur
negatiivsest
arvust).
*
Täpsuse kadu täisarvulisel jagamisel.
*
Täpsuse kadu tehetel reaalarvudega.
VEAD
VÕRDLEMISEL
*
Vale võrdlusmärgi kasutamine (range võrratuse asemel mitterange
võrratus).
*
Võrreldavate konstantide +-1 võrra vale väärtus.
VEAD
JUHTKONSTRUKTSIOONIDES
*
Tsükli lõpetamiseks vajalik tingimus ei osutu kunagi täidetuks.
*
Tsükli alustamiseks vajalik tingimus ei osutu kunagi täidetuks.
*
Tingimuslause (if tingimus then ...) on jäänud ilma alternatiivita
(else
...).
*
Valikulause (case ...) ei käsitle kõiki võimalikke väärtusi või
ei
informeeri
vigaste väärtuste esinemisest.
VEAD
ALAMPROGRAMMIDE KASUTAMISEL
* Tegelikud parameetrid on esitatud vales järjekorras.
4.2
Testimine
Programmi
testimisel on oluline, et toimuks psühholoogiline häälestumine
eesseisvale
tegevusele. Nimelt, TESTIMINE on programmi täitmise protsess
EESMÄRGIGA AVASTADA VIGU, mitte aga programmi täitmine eesmärgiga
näidata,
et programm töötab õigesti.
TESTIMISE
PROTSESS koosneb järgmistest tegevustest:
1)
Paneme eelnevalt kirja vajaliku komplekti algandmeid, mis valitakse
lähtuvalt
testimise meetodist. Ka testid lubamatute algandmetega tuleb
hoolikalt
välja töötada.
2)
Koostame testimise protokolli järgmise tabeli kujul
+----------------------------------------------+
|
Testandmed | Oodatav vastus | Tegelik vastus |
+------------+----------------+----------------+
| | | |
3)
Leiame oodatavad vastused ENNE testimist.
4)
Uurime hoolikalt iga testi tulemust.
5)
Kontrollime, kas programm ei tee seda, mida ta ei pea tegema (ehk ei
tohi
teha).
NB!
Pärast programmi parandamist tuleb teste alustada otsast peale.
TESTIDE
KOOSTAMISEL püütakse saavutada testide võimalikult väike arv ja
käsitsi
lahendamise lihtsus.
TESTIDE
KOOSTAMISE MEETODID jagatakse üldiselt kaheks - MUSTA KASTI
MEETODID
ja VALGE KASTI MEETODID.
MUSTA
KASTI MEETODID käsitlevad programmi kui "musta kasti",
s.t. uuri-
vad
selle käitumist lähtudes püstitatud ülesandest, sealjuures teadmata,
kuidas
programm seda ülesannet lahendab. Musta kasti meetoditeks on:
EKVIVALENTSIKLASSIDE
MEETOD. Võimalikud sisendandmed jagatakse niimoodi
klassideks,
et programm töötab iga klassiga ühtemoodi. Klassid tekita-
takse
ülesande põhjal sisendtingimuste ja muude aspektide ülevaatamise
teel.
Näiteks:
+---------------------------+----------------------+-------------------+
| Tingimus või aspekt | Õiged klassid | Valed klassid |
+---------------------------+----------------------+-------------------+
|
sisendsümbol kuulub hulka | | |
| | sisendsümbol õige | sisendsümbol
vale |
+---------------------------+----------------------+-------------------+
| | | |
Iga
vale klassi jaoks konstrueeritakse oma test, õigeid klasse tuleb
katta ühe testiga nii palju kui võimalik.
PIIRMISTE
VÄÄRTUSTE ANALÜÜSI MEETOD. Kontrollitakse programmi tööd
lubatud
väärtustega ja vahemike otsmiste elementidega ning nende
naabritega .
Samuti koostatakse testid, mis kontrollivad võrratuste
rangust.
OLETUSED
VIGADE KOHTA. Kogemustega programmeerijad ja testijad oskavad
ülesandega
tutvununa oletada võimalikku lahendusalgoritmi ja teavad
selle
juures vigade tegemise võimalusi.
VALGE
KASTI MEETODID lähtuvad sellest, et on täpselt teada, kuidas
programm
on kirjutatud. Üheks selliseks on TINGIMUSTE JA OTSUSTUSTE
MEETOD,
mille korral testid koostatakse põhimõtete kohaselt, et
1)
iga programmi lõik peab testimise ajal töötama
2)
iga tingimus peab olema täidetud mõlemas suunas.
Selle
teema lõpetuseks toon Teile ühe näite programmiga kaasas olevast
lühikesest
kasutajajuhendist:
Monty Pyton 's Complete Waste of Time
See ketas mahuga 676 Mb värskendab Teie igava Windows 'i ikoonikestega,
skriin-seiveritega,
tapeetidega (nii elavate kui ka surnutega), helidega
...
vähendab ärritust, depressiooni, närve ... üldiselt, kui Te
kõhkle-
te,
kas omada seda ketast või mitte, siis tuletame meelde: Igasugune
Teie
Otsus On Viga.
Täielik
aja raiskamine tühja, uisapäisa ja ilmaaegu nõuab:
-
386 või greiter IBM kompatiiblit arvutit koos vähemalt 4 Mb RAM'iga
-
256 kolor või better televiisorit
-
MS-hiirt või teist devaisi
-
WIN 3.1 või haier
-
DOS 3.3 või haier
-
MPC kompatiiblit helikaardi ja amplified spiikers või hedfones
haili
soovitatavad
-
CD-ROM olemasolu tööd ei sega
Trablite
laskmine (troubleshooting)
-
Veenduge enda vastavuses eeltooduga
-
Kui Teie monitor ei näita 600*480 või 800*600 punkti 256 värviga:
veenduge monitori olemasolus
-
Kui Teil on probleeme soundiga, veenduge, kas seda soundi üldse oli
-
Kui on probleeme mäluga: treenige mälu. Tapke maha kõik QEMM-id,
EMM-id
ja muud MMM-id. Ei aita: asjata tapsite.
-
Heli tugev/nõrk: ostke helitugevuse regulaator. Kui ei aita: pange
sisse
helikaart.
-
Ei jätku ruumi kettal: kustutage kõik mittevajalik. Ikka ei aita:
kustutage
ka vajalik. Või ostke uus vintsester.
-
Programm ei tööta kõigest hoolimata: Teil, paistab, on Dendy. Seda
trablit
niisama lihtsalt lasta ei saa.
Edukat
putukatejahti ja trablite laskmist! ;-)
Struktuur- ja
objektorienteeritud programmeerimise põhimõtted
Sissejuhatus
Programmide koostamisele tuleb läheneda märksa laiemalt, kui ainult
tegevusele, mis seisneb käskude rittapanemises. Sellest on olnud
juttu ka eelmistes teemades. Mida tähendab "läheneda
laiemalt"?
Nimelt on maailma tarkvaratootmises kaks põhilist lähenemisviisi -
struktuurne ja objektorienteeritud (lühendatult OO).
Lähenemisviis ei kehti ainult programmi kirjutamise kohta, vaid ka
probleemi analüüsimise ja programmi projekteerimise kohta.
Räägitakse ka erinevatest paradigmadest (paradigma on
komplekt mõisteid ja tõekspidamisi). Nende olemusest seekord juttu
teemegi.
Struktuurprogrammeerimine
Selle lähenemise sünniaastaks loetakse 1968, mil väljapaistev
hollandi programmeerimisteoreetik E. W. Dijkstra avaldas
artikli "GO TO lausest", milles ta nõudis, et
programm oleks lausete esinemisjärjekorras vabalt loetav, see
tähendab, et programmis ei oleks GO TO-st tingitud tagasihüppeid.
Isiklikust kogemusest võin väita, et on võimalik kirjutada
tuhandeid ridu pikki programme nii, et ei ole kordagi vaja kasutada
GO TO suunamislauset. See on ka tõestatud, et programmi saab kirja
panna ainult kolme konstruktsiooni - käskudejada, valikut
ja kordust - kasutades.
Struktuurprogrammeerimine taotleb, et igal programmikonstruktsioonil
oleks üks sisend- ja üks väljundpunkt,
aga GO TO lause võib tekitada mitu sisend- ja/või väljundpunkti.
Põhiliseks meetodiks struktuurprogrammeerimises on ülalt-alla
meetod. Selle põhiideeks on lähenemine probleemile kui
tervikule ja seejärel probleemi tükeldamine väiksemateks osadeks .
Siis toimub probleemide lahendamine sellisel viisil, et vaadeldakse
ainult käesoleval tasemel esilekerkinud ülesandeid ja
alamülesannete juurde pöördutakse alles pärast seda, kui
käesoleval tasemel on kõik tehtud. Sama printsiipi rakendatakse ka
programmi kirjutamisel ja testimisel.
Struktuurset lähenemist kasutades keskendame me esmalt tähelepanu
tegevustele ja protsessidele, struktuurprogrammeerimise
käigus vaatleme esmajoones funktsioone ja protseduure.
Kui on välja selgitatud vajalikud tegevused ja algoritmid, siis
teises järjekorras vaatleme nende tegevuste teostamiseks
vajaminevaid andmestruktuure. Kogu tarkvara arenguprotsessi
käigus ei püstitata nõuet, et andmed ja tegevused nendega oleksid
üksüheselt seotud. Piltlikult eksisteerib piir funktsioonide ja
protseduuride ning andmestruktuuride vahel, tihti on andmestruktuurid
globaalsed ja kõikide alamprogrammide poolt kasutatavad.
Struktuurne lähenemine on selle kontseptsioonide defineerimise ajast
olnud valitsev kogu maailma tarkvaratööstuses ja isegi uute ideede
võidukäigu ajal on leidnud oma kasutusala. Kuigi traditsioonilised
struktuursed programmeerimiskeeled on täienenud selleks, et
võimaldada OO lähenemist, ei kao sellega veel
struktuurprogrammeerimise stiil. See jääb objektide poolt
moodustatud eesriide taha kindlalt püsima.
Eesti keeles on struktuurprogrammeerimisest kirjutanud Rein Jürgenson
oma raamatus "Programmeerimine Pascal-keeles".
Objektorienteeritud programmeerimine
Peaaegu sama vana, kui on struktuurne programmeerimine, on ka OO
programmeerimine. Esimene OO programmeerimiskeel - Simula -
loodi juba 1967-l aastal. Tõsisema läbimurde tõi aga keele C++
loomine Bjarne Stroustrup'i poolt aastal 1983.
OO lähenemine probleemidele ja programmeerimisele on üldjoontes
täiesti erinev struktuursest lähenemisest. Keele C++ tugevaks küljeks on osutunud see, et C++ on täielikult kokkusobiv keelega C
ning OO lähenemine ja struktuurprogrammeerimine on mugavalt kokku
sulatatud.
Erinevalt struktuursest lähenemisest suunab OO lähenemise
kasutamine esmase tähelepanu andmetele ja alles seejärel
tõstatatakse küsimus, mida nende andmetega teha saab. OO lähenemine
püüab esitada programmis esinevaid andmeid ja nendega teostatavaid
tegevusi sarnastena meie igapäevases elus ettetulevatele
objektidele, kusjuures objekte kujutatakse 'intelligentsetena'.
Näiteks on meil objekt KALENDER. Küsides nüüd endalt, mida
KALENDER teha OSKAB, leiamegi selle objektiga seotud tegevused:
soovitud kalendrilehe näitamine ja lehekeeramine. Saite aru? Mitte
kalendri VAATAMINE vaid NÄITAMINE, sest kalender ise ei vaata. Ja
lehekeeramise laseme tal endal teha, seda võiks ta ju osata ;-)
Järgnevalt aga suundume objektide maailma ning tutvume selles
esinevate mõistete ja tõekspidamistega.
Objekt, atribuut, meetod
OO maailmas püütakse kõike, mille kohta kasutatakse nimisõna,
tituleerida objektiks . Kui on tegemist asjaga, millel on mingisugused
tunnused või omadused ning millega saab midagi teha või mis oskab
ise midagi teha, siis on see kindlasti vaadeldav objektina. Objekti
tunnuseid ja omadusi nimetatakse atribuutideks, objekti
tegevusi aga meetoditeks. Vaatame näiteks autot. Autol on
hulk mitmesuguseid väliseid ja varjatud tunnuseid: rataste
arv, värv, mootori võimsus jne. Auto
oskab liikuda , muuta suunda, kiirendada
ja pidurdada . Valides püstitatud ülesande lahendamiseks
vajalikud tunnused ja tegevused, võime defineerida objekti AUTO ja
seda oma programmis kasutada.
Klass
Kui tuletada meelde selle kursuse teist
teemat, siis sai räägitud andmeobjektidest ja
sellest, et igal andmeobjektil on olemas tüüp. Autot
kirjeldav objekt meie programmis on samal ajal ka andmeobjekt. Mis on
sellise andmeobjekti tüübiks?
OO lähenemine on selleks puhuks toonud sisse mõiste KLASS. Kui me
räägime umbmäärasest autost, siis tegelikult peame me silmas
autode klassi. Kõigil samasse klassi kuuluvatel objektidel on
samasugused atribuudid ja meetodid, objekte eristavad vaid
atribuutide erinevad väärtused. Klass on objekti jaoks sama mis
tüüp.
Klass on piltlikult väljendudes justkui plastmassist liivavorm,
millega saab liivakooke teha - kõik liivakoogid on sarnase
väljanägemisega. Objekt on üks konkreetne liivakook teiste
sarnaste hulgas.
Võtame näiteks klassi TASANDIPUNKT, millel on kaks atribuuti -
koordinaadid X ja Y. Igal klassil on vähemalt üks meetod, millega
tekitatakse objekte. Seda meetodit nimetatakse KONSTRUKTORIKS. Kui me
defineerime TASANDIPUNKTI konstruktorile ka kaks parameetrit, siis
võime selle abil tekitada palju uusi punkte konkreetsete X ja Y
väärtustega:
+--------------------------+ Objektid
|
Klass TASANDIPUNKT |
+--------------------------+ ==> A(1, 2)
|
Atribuut X | B(7, 9)
|
Atribuut Y | C(-17, 5)
+--------------------------+ ...
|
Konstruktor Punkt(x, y) |
|
Meetod Mine(x, y) |
|
Meetod YtleX |
|
Meetod YtleY |
+--------------------------+
Klassi juures defineeritud meetodeid saavad kasutada kõik sellesse
klassi kuuluvad objektid. Seega saame igale konkreetsele punktile
öelda, et ta läheks uuele kohale, samuti võime iga punkti käest
küsida, kus ta asub.
Kapseldumine
Klassi kirjelduses on harilikult esitatud nii atribuudid kui ka
meetodid. Üheks OO programmeerimise omapäraks on objekti
atribuutide peitmine teiste objektide eest. Sellist teguviisi nimetatakse kapseldumiseks.
Objekt
-
- - - - - - - - - - - - - - - -
Konstruktor Meetod1
| |
Meetod2
+============+
| | Atribuudid | Meetod3 |
Meetod4
+============+
| |
Meetod5 Meetod6
-
- - - - - - - - - - - - - - - -
Teistele objektidele jäävad paistma vaid meetodid, vaadeldava
objekti atribuutidele otse ligi ei pääse. Objekti enda meetodid
saavad aga atribuutidega kõike teha. Kapseldumine tagab selle, et
atribuutide väärtusi kasutavad ja muudavad vaid objekti enda
meetodid ning keegi väljaspoolt ei saa objekti olekut ja käitumist
atribuutide muutmise läbi ära rikkuda. Eespool toodud TASANDIPUNKTI
näite juures võib aru saada, et kui meil on kasutada klassis
defineeritud meetodid, siis ei teki meil vajadustki pöörduda otse
atribuutide X ja Y poole.
Sündmused ja teated
OO maailmas on tavaks rääkida, et objektid suhtlevad omavahel,
saates üksteisele teateid ja genereerides sündmuseid.
Mida see tähendab?
Mängime läbi ühe näite, kasutades selleks eespoolt tuttavaid
objekte klassist TASANDIPUNKT ja võttes juurde ka objekti TASAND,
kes neid punkte haldab. Lisaks on meil veel objekt nimega HIIR , mis
on Teie käele tuttava arvutihiire vari arvuti mälus. Olgu meie
programm koostatud selliselt, et hiire vasaku nupu vajutus tekitab tasandile uue punkti ja parema nupu vajutus kustutab lähima punkti.
Kuidas sellisel juhul elu programmis käib?
Hiire parema nupu vajutus genereerib sündmuse PNUPP_PUNKTIS(R,V).
See sündmus antakse tasandi kätte, mis kontrollib, kas koordinaadid
R ja V kuuluvad tema poolt kasutatavasse alasse. Kui jah, siis
tekitab ta tasandipunkti konstruktorit kasutades uue punkti: Punkt
A(R,V). Tekitatud punkt paneb saadud väärtused oma atribuutidele ja
võtab tasandil koha sisse.
Hiire vasaku nupu vajutus genereerib sündmuse VNUPP_PUNKTIS(R,V). Ka
see sündmus jõuab tasandi objektini ja käivitab järgmise
tegevuse: tasand saadab igale punktile teate, et punkt ütleks talle
oma koordinaadid (ehk kutsub välja punkti meetodid YtleX ja YtleY).
Iga punkti korral arvutab ta selle kauguse punktist (R,V) ja jätab
lähima meelde. Kui kõik punktid on üle küsitud, siis võtab ta
leitud lähima punkti ja hävitab selle ära.
Eks ole kena jutustus objektide elust? Tegelikult on sellisest
poeetilisest lähenemisest kasu, sest programmeerimisest kaugel
seisvatel inimestel (ka algajatel programmeerijatel) on sellise
mõtlemisviisiga lihtsam harjuda ning objektide omavaheline teadete
vahetamine on märksa arusaadavam kui funktsioonide ja
andmestruktuuride rägastikust läbimurdmine.
Pärilikkus ja polümorfism
Üheks väga oluliseks omaduseks objektide juures on võime pärandada
klassi informatsiooni teisele klassile. Mida see meile annab?
Olles kord defineerinud ja ära programmeerinud ühe üldise klassi,
nagu näiteks ISIK, ning tahtes luua uut spetsiifilist klassi, nagu
näiteks ÕPILANE, on meil võimalus pärandada kõik klassi ISIK
omadused (atribuudid ja meetodid) klassile ÕPILANE ning seejärel
lisada sinna juurde uusi omadusi. Sest sisuliselt on ju õpilane
samal ajal ka isik. Nii on võimalik korduvalt kasutada ühte
ja sama programmikoodi.
Objektide polümorfism tähendab seda, et objektid võivad
olla mitmepalgelised. Näiteks on meil klass KODULOOM ja
sellest pärandatud klassid KOER, KASS , LEHM ja HOBUNE. Klassil
KODULOOM on meetod TeeHäält. Igal pärandatud klassil on see
meetod üle defineeritud nii, et ta vastaks konkreetse klassi
spetsiifikale. Kui nüüd kasutada erinevate koduloomade hulka ja
otseselt teadmata, mis klassi looma me oleme sellest hulgast välja
valinud, siis meetodi TeeHäält tulemus vastab konkreetsele
klassile - koer haugub, kass näub jne. Programmeerija ei pea enam
ennast vaevama sellise koodi kirjutamisega, et "kui on
tegemist koeraga, siis kasuta haukumist muidu kui tegemist on
hobusega, siis kasuta hirnumist muidu ..." jne.
Mis on kasu objektorienteeritusest?
OO keeltes on objektide klassi kirjeldus harilikult eraldatud selle
klassi meetodite teostusest. Selline eraldatus on fundamentaalse
tähtsusega, sest see võimaldab korraldada klasside taaskasutamist
ja vähendada seega tarkvara loomiseks vajalikke jõupingutusi.
Kasutajal on vaja vaid tutvuda vaadeldava klassi objektide
käitumisega, mis paistab harilikult välja klassi kirjeldusest ning
ta ei pea midagi teadma sellest, kuidas sellise klassi meetodid on
teostatud. Taaskasutamise mõttes võib klassi vaadelda kui "musta
kasti", millel on konkreetsed omadused ja käitumine, aga
mille sisemust näha ei ole.
Teiseks oluliseks omapäraks on programmi vigade lokaliseerumine .
Nii, nagu klassi taaskasutaja "ei näe" klassi
teostust, nii ei mõjuta klassi meetodi teostuse vead midagi
väljastpool klassi piire olevat. Lihtsalt selle klassi objekt käitub
"imelikult". Kui struktuurprogrammeerimise
nuhtluseks oli tihti vigade ahelreaktsioon , mis tulenes sellest, et
ühe vea parandamine võis tekitada uue vea, siis OO programmeerimine
on sellisest efektist vabanenud just tänu vigade kapseldumisele
meetodite sisse. See annab tohutu ajavõidu programmide silumisel.
Objektorienteeritud maailm
Tänapäeva tarkvaratootmine on suurel määral objektorienteeritud.
See on ju moodne! Erinevalt riietumismoest on see mood
tingitud praktilisest lähenemisest - objektorienteeritud
tarkvaratootmine on odavam. Te võite ju küsida, et millised on siis
tulemused?
MS Windows ja teised graafilised kasutajaliidesed on sügavalt
objektorienteeritud, samuti suurem enamus nende all töötavatest
rakendustarkvara pakettidest. Üha enam arenevad OO
andmebaasisüsteemid.
Juba seitsmekümnendatel aastatel saadi aru, et vajadus uute
programmide järele kasvab kiiremini kui võimalus neid vajadusi
rahuldada. OO lähenemine annab lootust, et programmeerimine
tulevikus hakkab sarnanema valmis objektide kokkuladumisega
ülesandele nõutava lahenduse saamiseks. See on siis nagu LEGO klotsidega mängimine - juba algusest peale on teada, et need klotsid sobivad kokku, määravaks osutuvad klotside omadused ja nende
paiknemise kord. See kõik võimaldab vähendada programmide
koostamisele minevat aega ja kunagi ehk jõuda kõigi infotöötlemise
vajaduste rahuldamiseni.
Kõik kommentaarid