Autori risto postitused

PR2ET4: Struktuurid 2 ja lihtne päis

Labori materjal

Laboriülesanded

Selleks laboriks on ülesanne mis on jaotatud kahte ossa.

Laboriülesande 1. osa: Seostatud andmete väljastamine

Selles osas trükime välja failidest loetud andmed. Selleks on oluline õigel hetkel teha vajalikud seostamised kahe struktuuri vahel.

Andmefailid

Andmed on sulle antud kahes eraldi failis, mille kirjeldamiseks kasutame olemi-suhte diagrammi (ERD ehk entity-relationship diagram).

NB! Selliseid suhteid näidatakse sageli ka UMLi klassidiagrammina. Vaata all viidet selle kohta!

Olemi-suhte diagrammi kardinaalsus

  • Ühel isikul võib olla 0 või enam sõidukit
  • Iga sõiduk peab kuuluma täpselt ühele isikule

Andmed kahes failis on seostatud Eesti isikukoodi (person_id) abil.

Lae andmefailid alla siit: https://blue.pri.ee/ttu/files/iax0584/andmefailid/4_data.zip

Nõuded
  • Kasuta programmi programmis päisefaili. Paiguta sinna struktuuride deklaratsioonid, makrod ja funktsioonide prototüübid, vajadusel ka loendid.
  • Loe kahest antud failist andmed eraldiseisvatesse struktuurimassiividesse.
    • Väldi keerukaid lahendusi (pesastatud struktuurid või struktuuriviidad) selle laboriülesande lahendamisel.
    • Isikukoodi pead hoiustama 64-bitise täisarvuna. Sedasi vähendad protsessoritsüklite arvu mis kulub väljade võrdlemiseks!
      Use inttypes.h !
  • Harjuta viidaaritmeetikat
    • Kasuta nooleoperaatorit (->) struktuuri liikmete poole pöördumiseks
    • Väldi nurksulgude [] kasutamist massiivide indekseerimisel.
  • Sorteeri isikute andmed eesnime alusel tähestikulises järjekorras kasvavalt.
  • Trüki välja isikuandmed, millele järgnevad kõik nendega seotud sõidukid.
    • Omaniku andmed tohid trükkida ühekordselt.
    • Omaniku info järel loetle kõik nendega seotud sõidukid
    • Kui isikul puuduvad sõidukid, anna sellekohane teavitus.
Soovituslikud funktsioonid

NB! Tegu on soovitusliku loeteluga. Sinu loodavad funktsioonid ning nende parameetrid võivad sellest erineda.

Testimine

Järgnev on ülesande esimese osa oodatav väljund

Laboriülesande 2. osa: Maksude arvutamine

Teises osas kirjutame laienduse esimesele osale. Kõik esimeses osas olnud nõuded kehtivad ka siin.

Nõuded
  • Leia ja kuva palju iga omanik makse maksma peab
    • Kuvada tuleb nii summa kui protsendina sissetulekust
    • Lisa hoiatus kui maksud ületavad 10% isiku aastasest sissetulekust.
    • Väljasta veateade kui inimesel puuduvad sissetuleku kohta andmed.
    • NB! Meenuta, et funktsioonid peaksid vaid ühte asja tegema. Ära pane arvutamist samase funktsiooni kus andmeid väljastad või faile loed! Tee eraldi funktsioon maksude leidmiseks.
  • Vihje: Lisa struktuuri täiendav liige või liikmed, et saaksid hoiustada ja kuvada maksuandmeid. Struktuuri liikmed ei pea olema 1:1 vastavuses sellega mis on hoiustatud failis, täiendavate väljade lisamine või isegi andmete töötlemine ja teises formaadis hoidmine mälus on OK.
Soovituslikud funktsioonid

NB! Tegu on soovitusliku loeteluga. Sinu loodavad funktsioonid ning nende parameetrid võivad sellest erineda.

Testimine

Järgnev on ülesande teise osa oodatav väljund

Pärast seda tundi peaksid

  • Oskama luua ja seostada päisefaili oma koodifailiga
  • Teadma mida pannakse ja mida ei panda päisefaili sisse
  • Teadma tüüpilisi kasutusjuhte päisefailidesse
  • Teadma erinevaid mis vahet on noolsulgudel ja ümarsulgudel päisefaili lisamisel ning kust siis neid faile otsima hakatakse
  • Teadma kuidas makrotena luua tingimuslauseid eelprotsessori jaoks
  • Teadma miks on vajalikud ning oskama kasutada kaitseid päisefailidel
  • Oskama silumislauseid koodi põimida erinevatel viisidel
  • Oskama algväärtustada struktuure
  • Oskama struktuure pesastada (st ühe struktuuri liikmeks on teine struktuur või struktuuri viit)
  • Oskama struktuure tagastada
  • Oskama kasutada struktuuri ligipääsuoperaatorina noolt ning teadma millal seda teha tuleb
  • Oskama viidaaritmeetikat kasutada struktuurimassiivide peal
  • Oskama lugeda lihtsamaid ERD diagramme ja teadma, et neid kasutatakse andmemudelite modelleerimiseks.
  • Teadma, et UMLis on ka olemas klassidiagrammid ning klassidiagramme kasutatakse andmemudelite modelleerimiseks.

Täiendav materjal

PR2ET3: Struktuurid

Labori materjal

Laboris lahendatakse kommenteeritult koos läbi failist struktuuridesse lugemise näide. Neile kes ei osale laboris on see avaldatud koodinäitena: Failist struktuurimassiivi lugemise näide

Laboriülesanded

Selles laboris on üks ülesanne, millele lisandub 4 edasijõudnute ülesannet.

Ülesanne: töötajate otsing

Selles programmis matkime töötajate andmebaasi, kust on võimalik filtreerida välja töötajate andmeid vastavalt etteantud otsinguparameetrile.

Andmefail

Lae alla testandmed järgnevalt lingilt: https://blue.pri.ee/ttu/files/iax0584/andmefailid/3_data_short.zip

Andmefail koosneb juhugeneraatoriga loodud andmetest.

Nõuded
  • Loe failist ettevõtte töötajate andmed
    • Failis on iga rea kohta üks kirje
    • Iga andmeväli on eraldatud tühikuga. Andmeväljad on ühesõnalised.
    • Andmete struktuur failis
      <eID> <first_name> <last_name> <city>
  • Programmis tuleb andmeid hoida struktuuridest koosnevas massiivis.
  • Programm peab töötama olukorras kus andmete täpne arv pole teada ning see võib ajas muutuda (näiteks mõni rida lisatakse või kustutatakse).
    • Loo programmile mõistlik limiit ning veendu, et sellest üle ei mindaks!
  • Luba programmi kasutajal teostada otsingut linna nime järgi
    • Programm väljastab kõik töötajad, kes sisestatud linnas elavad
    • Näita mitu vastet mitmest leiti (nt [0 / 91])
    • Otsingut peab saama sooritada korduvalt ilma programmist väljumata
    • Baasülesandes väljasta kõik andmed – isikukood, perenimi, eesnimi, linn
  • Kasutajal peab olema võimalus programm sulgeda, loo selle jaoks eraldi võimekus (näiteks sisestades kindel käsk)
  • Korduv faili lugemine programmi sees ei ole lubatud.
  • Struktuuri sisu ei pea olema üks-ühele faili sisuga! Väljade lisamine on kasulik eelkõige lisaülesannete lahendamisel.
Programmi näidisväljund

NB! Programmi väljund on näide lahendusest pärast kõigi nelja edasijõudnute ülesande lahendamist!

Ava mind väljundi nägemiseks

Edasijõudnute ülesanne 1: struktuuride sorteerimine

Nõuded:

  • Leitud töötajate loetelu peab olema sorteeritud perekonnanime järgi tähestikulises järjekorras kasvavalt.
  • Väljastuse nime formaat peab olema perenimi, eesnimi

Edasijõudnute ülesanne 2: linnade nimistu

Nõuded:

  • Kuva kasutajale kõik failis olevad linnad
  • Linnade nimekiri koostatakse programmi poolt töö ajal, vastavalt sisendfailis esinevatele linna nimedele
  • Kasutaja peab saama linnade nimekirja kuvada sisestades selleks vastava käsu. Käsk tuleb lisada menüüsse
  • Linnade nimekirja peab saama kuvada korduvalt
  • Linnade nimekirja tohib koostada programmi töö vältel vaid ühe korra.

Edasijõudnute ülesanne 3:  Mugavam otsing

Nõuded

  • Otsing ei tohi olla tõstutundlik. Näiteks otsides otsides linna TALLINN  või tallinn , tuleb kuvada kõik töötajad, kes elavad Tallinnas.
  • Otsing peab toetama osalist vastet. Näiteks otsides all  leitakse nii need, kes elavad Kallastel, kui ka need, kes elavad Tallinnas.
  • Mõlemad peavad töötama ka korraga. St eelnev tulemus peab olema leitav ka otsides ALL  või aLL

Edasijõudnute ülesanne 4: Töödeldud isikukood

Nõuded

  • Ära kuva vastuste hulgas enam isikukoodi
  • Kuva töötaja sünniaeg formaadiga d. MMMM yyyy

Isikukoodi formaadi kohta saad lugeda: https://www.riigiteataja.ee/akt/114022017005

Vajuta mind, et näha selgitusi kuupäeva ja kellaaja vormingu kohta

m – Minutid vahemikus 0 – 59.
mm – Minutid vahemikus 00 – 59. Minutitele 0 – 9 lisatakse ette number null.

h – Tunnid vahemikus 1 – 12.
hh – Tunnid vahemikus 01 to 12. Tundidele 1 – 9 lisatakse ette number null.
H – Tunnid vahemikus 0 – 23
HH – Tunnid vahemikus 00 – 23. Tundidele 0 . 9 lisatakse ette number null.

d – Päevad vahemikus 1 – 31
dd – Päevad vahemikus 01 – 31. Päevadele 1 – 9 lisatakse ette number null.
ddd – Päevad lühinimega ( E / Mon; T / Tue; K / Wed; …)
dddd – Päevad täispika nimega (esmaspäev / Monday; teisipäev / Tuesday; kolmapäev / Wednesday; …)

M – Kuud vahemikus 1 – 12
MM – Kuud vahemikus 01 – 12. Kuudele 1 – 9 lisatakse ette number null.
MMM – Kuu lühinimi (jaan / Jan; veebr / Feb; märts / Mar; apr / Apr; …)
MMMM – Kuu täispika nimega (jaanuar / January; veebruar / February; Märts / March; …)

y – Aasta vahemikus 0 – 99
yy – Aasta vahemikus 00 – 99
yyy – Aasta, minimaalselt kolme numbriga (1 -> 001; 15 -> 015; 145 -> 145; 1949 -> 1949)
yyyy – Aasta nelja numbriga

Pärast seda tundi peaksid

  • Teadma kuidas deklareerida uusi struktuure – st uus andmetüüp, milleks on struktuur
  • Oskama valida struktuuri liikmeid
  • Teadma mis on struktuuri polsterdamine ja joondamine ning kuidas see mõjutab struktuuri suurust mälus
  • Teadma mis mõjutab struktuuri suurust
  • Teadma millised operaatorid on kasutusel struktuuri liikmete poole pöördumiseks ja oskama kasutama punkt-operaatorit
  • Teadma kuidas luua struktuuridest koosnevat massiivi ja lugeda andmeid failist struktuurimassiivi
  • Teadma kuidas omistada terviklikku struktuuri
  • Teadma kuidas defineerida andmetüüpe ümber, andes neile uue nime (typedef)

Täiendav materjal

PR2ET2: Loendid

Labori materjal

Labori ülesanded

Laboris on 2 ülesannet. Enamjaolt on tegu kordamisülesannetega meenutamaks Programmeerimine 1 ainet, kuid ülesandeid on rikastatud loendite kasutamisega ning mõlema ülesande puhul saame juba kasutada eelmise nädala viitade teemat enda elu lihtsustamiseks.

Ülesanne 1: Failide kategooriad

Selles ülesandes loome tööriista, mis suudab kategoriseerida ja loendada faile vastavalt faili nimes olevale faili laiendile. Näiteks saame leida mitu dokumendifaili asub määratud kaustas ja selle alamkaustades. Ülesande raames loome vaid osa programmist, mis tegeleb laiendite tuvastamise ja loendamisega.

Failide nimede leidmiseks kasutame eelmisel semestril Linuxi laboris õpitut. Kasutades tööriista find  otsime üles kõik failid rekursiivselt ning kasutades toru (pipe) suuname otsingu tulemused enda programmi loendamiseks.

NB! Lahenduse potentsiaali testimiseks on vaja Linuxit. Lihtsaim on testida seda kooli keskkonnast (st kasutades kooliarvutit, Horizongate’i või luues SSH tunneli kooli serveritesse / arvutitesse). 

Nõuded

Loo programm, mis täidab järgmised nõuded

  • Programm võtab vastu teadmata arvu faili nimesid standard sisendvoost ( stdin )
    • Eelnevalt sisendite arvu küsimine ega erilise sisuga sõne kasutamine lugemise peatamiseks pole lubatud
    • Lugemine tuleb peatada ja statistika kuvada pärast seda kui programm saab EOF  (end of file, faili lõpp) signaali.
  • Kategoriseeri failid vastavalt etteantud loetelule laienditest ja gruppidest.
  • Näita mitu faili igasse gruppi kuulus
  • Kategooriate tuvastamiseks koodis pead kasutama loendi andmetüüpi (enum)
  • Üks funktsioon on sulle ette määratud. Funktsioon saab parameetrina kaasa faili laiendi sõnena ning tagastab vastava loendi väärtuse millisesse kategooriasse fail kuulub. Kasuta järgnevat prototüüpi:
    enum FileCategory GetFileType(char *extension);
  • Programm tohib kasutajale anda informatsiooni programmi kohta (nt mida teha tuleb) pärast käivitamist. Programm ei tohi sisendite vahel ekraanile teksti väljastada (st nt kahe faili nime sisestamise vahel).
Kategooriad ja laiendid
  • Arhiivid: zip, rar, 7z, tar, gz
  • Andmed: csv, xls, xlsx, ods
  • Dokumendid: pdf, doc, docx, rtf, odt
  • Programmikood: c, h, cpp, hpp, py
  • Tekst: txt
  • Pildid: jpg, jpeg, png, svg,
  • Muu: Kõik teised failid, millel on laiend, kuid ei olnud eelnevas loetelus.
  • Laiend puudub
Koodi mall

Selleks, et sulle veidi aimdust anda kuidas lugemine ja töötlemine võiks välja näha pakun välja selleks sobiliku malli.

Soovituslikud sammud ülesande lahendamisel
  1. Lisa koodi funktsioon, mis parandab sõne lõpus oleva reavahetuse.
    Näiteks void FixTrailingNewline(char *str);
  2. Lisa koodi funktsioon, mis leiab viimase punkti asukoha sõnas, et hiljem tuvastada faili laiendi algus selle põhjal.
    Näiteks: int GetLastPointPos(char *str);
  3. Lisa koodi failikategooria loend ning loo vastav algväärtustatud loendurite massiiv.
  4. Lisa koodi funktsioon loendurite massiivi väljastamiseks
  5. Lisa koodi funktsioon, mis leiab laiendile vastava loendi väärtuse.
    Näiteks:  enum FileCategory GetFileType(char *extension);
Vihjeid ja hoiatusi
  • Vaata läbi täiendav loendite näide. See on üsna sarnane praegusele ülesandele ja peaks sulle andma hea idee struktuurist ja kasutusest.
  • Ülesandes peaksid ära tundma tükke eelmisest semestrist – nt sõnede esimene ja teine tunnitöö, samuti vanuselise grupeerimise kodutöö.
  • Kui kasutad loendi elementide väärtusteks automaatset numeratsiooni ja lisad soovitud elementide lõppu veel ühe elemendi, siis selle väärtuseks saab elementide arv loendis ilma selle viimase elemendita.

    Sedasi saad lihtsustada näiteks massiivide deklareerimist mille pikkus on vastavate loendurite arv.

  • Kasutades viitade omadusi (nt viidaaritmeetika), saad punkti asukoha põhjal lihtsasti leida punktile järgneva tähemärgi aadressi, mis on samuti sõne ning saab olema olemuselt viit faili laiendile.
  • Lugemistsükli pikkus ei ole määratud. Saad näiteks kasutada funktsiooni fgets()  – see funktsioon tagastab  NULL -viida kui tuvastab faili lõppu tähistava  EOF  (end of file) signaali.
  • Meeldetuletuseks! fgets()  salvestab reavahetuse sümboli sõnesse. Selle pead likvideerima!
  • Kogu programmi sisend tuleb sulle läbi toru sinu programmi stdin standardvoogu.
  • Kiireks testimiseks saad klaviatuurilt saata EOF  signaali kasutades klahvikombinatsiooni  ctrl+d .
Käsitsi testimine

Programmi käsitsi testimiseks käivitame programmi tavapäraselt ja trükime seejärel failide nimesid, vajutades iga nime järel enter klahvi. Kui soovime sisestust lõpetada, vajutame klahvikombinatsiooni  ctrl+d  – see saadab EOF i ehk faili lõpu signaali.

Terviklik testimine

Selleks, et testida su programmi tööd kui terviklikult olen ette valmistanud ühe võrgukettal paikneva kausta. Sinu tulemused peaksid vastama 1:1 näitega.

Failide otsimiseks kasutame sisseehitatud tööriista find, mida kasutatakse kaustade ja failide leidmiseks. Esmalt määrame kust otsime, seejärel tüübiks failid (vältimaks kaustade nimesid) ning trükime välja vaid faili nimetuse ilma asukohata. Tulemused edastatakse toru abil sinu programmi.

Näide on käivitatud käsuga: find ~/M/risto.heinsar/lab_cat/ -type f -printf '%f\n' | ./task1_category

Vihje: Mängi sellega – vaata näiteks kuidas jaotuvad failid sinu P kettal, lisa täiendavaid kategooriaid, failitüüpe.

Varukoopia juhuks kui ülikool võrk maha läheb

Juhul kui sa ei saa demonstreerida ülesande toimivust kuna ülikooli võrgu või arvutitega on probleeme, saad kasutada järgnevat arhiivi. Tegu on täpse koopiaga M kettal asuvatest failidest ja kaustadest.

https://blue.pri.ee/ttu/files/iax0584/andmefailid/2_1_file_cat_directory_structure.zip

Ülesanne 2: Pikkuste teisendaja

Sulle on edastatud andmed rahvusvahelise ettevõtte töötajate liikumisaktiivsuse kohta. Sinu ülesandeks on kõik saadud andmed teisendada ühte kasutaja poolt soovitud mõõtühikusse, seejärel kuvada tulemused ja esmane statistika.

Nõuded
  • Programm võtab käsurealt 2 argumenti
    • Esimene argument on faili nimi
    • Teine argument on soovitud ühik milles väljundit näidata (sobilikud väljundid on  m  meetrites, ft  jalgades ja  km  kilomeetrites)
  • Sisendfail on lihtne tekstifail (antakse esimese käsurea argumendina)
    • Iga rida failis on üks kirje
    • Iga kirje koosneb kahest väljast, mis on tühikuga eraldatud: <distants> <ühik>
    • Distantsid on antud reaalarvuna
    • Ühikud on antud sõnena. Sisendfailis on distantsid antud ainult meetrites või jalgades.
  • Leia ja kuva ühel real algne distants ja distants mis on teisendatud soovitud ühikusse (antud käsurea teise argumendina)
  • Leia ja kuva kogu läbitud distants ja keskmine läbitud distants.
  • Kõik pikkused kuva kahe komakohaga.
  • Ühikud tuleb programmis kodeerida loendina (enum). Soovituslik loendi deklaratsioon on järgmine:
  • Teisenduse konstandid mida saad kasutada oma koodis:
Andmefailid

Selle ülesande testimiseks on kolm andmefaili. Loe täpsemalt Testimine peatüki alt mida tähele panna ning veendu tulemuste korrektsuses.

Lae andmefailid alla siit: https://blue.pri.ee/ttu/files/iax0584/andmefailid/2_2_converter_data.zip

Vihjeid

Selles ülesandes on korraga kolm erinevat ühikut (võiks olla ka rohkem!) ning nende trükkimine sedasi, et kood loetavaks jääb võib muutuda keerukaks. Kaks ideed kuidas seda lahendada.

Valik 1: Loo funktsioon ning kutsu see välja iga kord kui on vaja ühikut trükkida ekraanile. Ühik anna kaasa loendi väärtusena.

Valik 2: Loo funktsioon, mis tagastab viite sõnele, mis omakorda sisaldab sobilikku ühikut. Kuna ühik on kirjutatud funktsioonis konstandina, siis funktsiooni eluiga probleemiks ei osutu. Sellise funktsiooni eelis on see, et saad väga mugavalt printida ühikut keerulisema printf lause sees – nt  printf("%.2f %s\n, distance, ReturnPrintableUnit(unit));

Testimine

Selle programmiga on palju erinevaid asju mis võivad valesti minna. Testi kõiki järgnevaid olukordi!

Testid 1 – 3: Vale argumentide arv

Siin on kombineerituna näha kolm erinevat testi, kõigi nende käigus testime probleeme käivitamisel (vale argumentide arv)

Testid 4, 5: Probleemsed argumendid

Järgneva kahe testi vältel vaatame antud argumentide sisse. Veendume, et ühik on toetatud ning fail eksisteerib.

Test 6: tühi fail

Olukorras kus sisendfail on tühi on meie programmis samuti ohukohti. Veendume, et programm ei jookseks kokku tühja faili puhul!

task2_data1.txt sisu:

Võimalik väljund:

Testid 7 – 9: Teisendused

Selles testis käime läbi kõik võimalikud sisendi ja väljundi kombinatsioonid mis on meil toetatud. Kasutame lihtsat andmefaili, et vastuseid parem jälgida oleks.

task2_data2.txt sisu:

Oodatav väljund:

Test 10: Pikem fail

Selle testi puhul on peamiseks eesmärgiks proovida tulemusi pikema andmefaili korral ja veenduda, et midagi kahe silma vahele ei jäänud.

task2_data3.txt sisu:

Oodatav väljund:

Märkus! Kas panid tähele mida me ei testinud?

Edasijõudnutele: laiendatud teisendaja

Edasijõudnute ülesanne on teise laboriülesande laiendus. Mõtle ülesandest kui pikkuste teisendajast mis väljastab ka lihtlabase statistika

Nõuded
  • Lisa tugi täiendavatele ühikutele
    • Jard (yard, yd)
    • Toll (inch, in)
    • Detsimeetrid (dm, decimeter)
  • Teisendused kuue toetatud ühiku vahel peavad olema toetatud mõlemas suunas (st mõlemad kõik nendest võivad olla nii sisendiks kui väljundiks)
  • Lahenduse disain peab olema lihtsasti laiendatav. St täiendavate ühikute lisamine ei tohiks vajada suuremahulisi koodi ümberkirjutamisi. Teisenduse kood täiendavate ühikute lisamisel ei tohi kasvada eksponentsiaalselt!

Hoiatus: Kuigi antud ülesande oodatav lahendus on lihtsasti hallatav, tekitab see täiendavaid vigu ühikute teisenduskordajate ümardamise tõttu. Ole sellega ettevaatlik suurt täpsust nõudvates probleemides.

Pärast seda tundi peaksid

  • Oskama töötada loenditega, sh
    • Deklareerida uusi loendi tüüpe
    • Deklareerida loendi tüüpi muutujaid
    • Edastada funktsiooni ja tagastada funktsioonist loendeid.

Täiendav materjal

NB! Ettevaatust koodimisstiiliga järgnevate viidete puhul. Mitte ükski neist ei suuda isegi ühel leheküljel sama koodimisstiili reegleid jälgida!

PR2ET1: Viidad

Labori materjal

Meeldetuletuseks koodimisstiilist

  • Su kood peaks olema lihtsasti loetav
  • Stiil peab üle kõigi koodifailide olema samasugune
  • Eelista lihtsust – lihtsad lühikesed funktsioonid, arusaadavad algoritmid, väldi keerukuse tekitamist koodi “uhkemaks” tegemiseks
  • Kommenteeri oma koodi!
  • Planeeri oma kood modulaarsena (lühikesed lihtsad funktsioonid, mis on universaalsed ja mida saad kergesti kopeerida ühest programmist teise, sh tulevikus ka eksamil või kontrolltööl).
  • Kasuta kiireid algoritme ja andmestruktuure (minimaalselt seni õpitute hulgast)
  • Väldi globaalmuutujaid (selles aines näeme ka olukordi kus globaalmuutujad on OK)

Ülesanded

Selles laboris on kaks ülesannet. Teine ülesanne on tükeldatud kahte ossa. Edasijõudnute ülesanne on ehitatud teise ülesande põhjal.

Ülesanne 1: viidad ja muutujad

Tegu on klassikalise muutuja väärtuse vahetamise ülesandega.

Lae alla ülesande aluskood: https://blue.pri.ee/ttu/files/iax0584/aluskoodid/t1_swap_template.c

Nõuded
  • Ehita oma lahendus aluskoodile
  • Aluskoodis on koodilõigud, mille lõpetamine on jäetud sinu ülesandeks. Need on märgitud koodis kommentaariga TODO .
  • Loo 2 funktsiooni vastavalt aluskoodis olevatele kommentaaridele. Ühest neist tuleb väärtused sisse lugeda ja teises nende väärtused omavahel vahetada. Mõlemate puhul kasuta viitade võimalusi.
  • Trüki välja muutujate mäluaadressid kolmes erinevas kohas
    • Esiteks main funktsioonis, näita kus kohas väärtused asuvad mälus
    • Teiseks lugemise funktsioonis – näita kuhu kohta loetavad väärtused salvestatakse
    • Kolmandaks vahetamise funktsioonis – näita kus asuvad need väärtused mida parasjagu vahetad.
  • Kaitsmisel selgita mis on kuvatud väärtuste puhul oluline!
Testimine

Ülesanne 2 osa 1: Viidad ja massiivid

Teises ülesandes vaatleme täisarvudest koosneva massiivi liikmete mäluaadresse ja kasutame viitade võimalusi, et funktsioonist mitu väärtust korraga välja saada. Samuti harjutame viidaaritmeetika kasutamist.

Nõuded

Loo programm, mis täidab järgnevad nõuded

  • Selles ülesandes ei tohi sa kasutada nurksulge [] massiivi indekseerimiseks, vaid pead rakendama viida-aritmeetikat. Nurgsulge tohib kasutada vaid massiivi deklareerimiseks.
  • Kogu selle ülesande vältel ei tohi sa kasutada nurksulge massiivide indekseerimiseks. Kasutada tuleb viida-aritmeetikat.
  • Loo funktsioon, mis loeb sisse 10 numbrit. Salvesta need kõik massiivi.
    Meeldetuletus: Massiiviga koos tuleb edastada funktsioonile ka selle pikkus.
    Vihje: loe need kas failist või kasuta voo suunamist, et säästa enda aega programmi testimisel!
  • Loo funktsioon, kus trükid välja kõik loetud arvud ning nende asukoha mälus.
  • Loo funktsioon, mis leiab korraga nii minimaalse kui maksimaalse arvu massiivist
    • Seda funktsiooni tohid välja kutsuda vaid ühe korra, mõlemad tulemused tuleb leida selle käigus.
    • Funktsiooni ei tohi tagastada midagi (st tagastuse tüüp on  void ).
    • Võid eeldada, et eksisteerib vaid üks vähim ja üks suurim arv.
    • Kasuta viitade võimalusi kahe väärtuse funktsioonist kätte saamiseks.
      • Ära kasuta massiive min/max väärtuse salvestamiseks!
      • Ära väljasta tulemusi loodava funktsiooni sees!
  • Kõik funktsioonid tuleb kutsuda välja main() funktsioonist. Minimaalne ja maksimaalne väärtus väljasta samuti main() funktsioonis.
Testimine

Esimese osa oodatav väljund

Ülesanne 2 osa 2: massiiv on viit esimesele liikmele

Selle ülesande eesmärk on veenduda, et mõistad korrektselt ideed “massiiv on käsitletav kui viit esimesele massiivi liikmele”.

Nõuded
  • Loo (või korduvkasuta) funktsioon, mis suudaks massiivist välja trükkida n numbrit ja mäluaadressi.
  • Funktsioonil tohib olla vaid 2 parameetrit.
  • Funktsioon peab olema ehitatud sedasi, et see suudaks väljastada ükskõik millise etteantud massiivi
  • Näitamaks, et su funktsioon on tehtud õigesti (ning veelgi enam, tõestamaks, et mõistsid teemat õigesti), kutsu loodavat funktsiooni välja 3 korda sedasi, et
    • esimene kord trükitakse välja kogu massiiv
    • teine kord trükitakse välja vaid elemendid 0 – 4
    • kolmas kord trükitakse välja elemendid 3- 7

Vihje: Mõtle enne hoolikalt kui hakkad funktsiooni koostama! Ülesande eesmärk on veenduda, et sa massiivi ja viida omavahelisest seosest õigesti aru.  Ülesande eesmärk ei ole luua ülimalt keerulist või kavalat lahendust!

Testimine

Oodatav väljund pärast teise osa lahendamist

Edasijõudnutele: minmax koos aadressidega

Selles ülesandes taasloome ül. 2 esimeses osas loodud ekstreemväärtuste leidmise funktsiooni. Teeme muudatuse mis lubab meil lisaks väärtusele saada ka asukoha, jällegi kasutades viitade omadusi

Nõuded
  • Loo uus funktsioon või muuda olemasolevat sedasi, et leida minimaalse ja maksimaalse arvu asukoht. Funktsioon peab leidma mõlema asukoha ühe käivitusega.
  • Funktsiooni ei tohi tagastada midagi (st tagastuse tüüp on  void ).
  • Funktsioonil tohib olla täpselt 4 parameetrit
    • Massiiv arvudega
    • Massiivi pikkus
    • 2 viita või topeltviita – mõtle välja mis nendes hoida sobiks!
  • Trüki välja järgnevad tulemused main funktsioonis
    • Minimaalne ja maksimaalne arv
    • Minimaalse ja maksimaalse arvu aadressid massiivis
    • Minimaalse ja maksimaalse arvu indeksid massiivis
    • NB! Aadressi ja indeksi leidmiseks ei tohi sa täiendavalt massiivi uuesti läbi käia! Tulemused saamiseks tuleb kasutada viitade omadusi ja arvutada vastused funktsioonist saadavate tulemuste põhjal!
Testimine

Edasijõudnute ülesande oodatav väljund

Pärast seda tundi peaksid

  • mõistma aine nõudeid, sh kuidas hinne kujuneb
  • teadma mis on viit
  • oskama mõista mäluaadressi iseloomu
  • tegema vahet virtuaalsel ja füüsilisel aadressil
  • teadma mis mõjutab mäluaadressi suurust
  • teadma täiendavast mäluvajadusest ja keerukusest mis tuleb viitade otsese kasutamisega
  • oskama viitmuutujat deklareerida
  • teadma kuidas viitadega koodi kirjutada lähtuvalt koodimisstiilist
  • teadma mis tähtsus on viida andmetüübil
  • teadma mis on  NULL-viit ja kus seda kasutatakse
  • teadma mõningaid valdkondi kus viitasid kasutatakse
  • teadma ja oskama kasutada viida-aritmeetikat
  • mõistma scanf argumente ja kuidas viidad ning aadressid siin mängu tulevad
  • mõistma miks me eelmine semester ütlesime, et massiivi edastamisel manipuleerime originaalandmeid ning muutujate puhul mitte
  • osksama muutujate mäluaadresse funktsioonidesse edastada
  • oskama mitme muutuja väärtust ühe funktsiooni sees manipuleerida kasutades viitasid
  • mõistma topeltviida ideed
  • oskama kasutada tingimuslausete koostamiseks kolmikoperaatorit

Täiendavat materjali

6. labor: Funktsioonid

Labori materjal

Esitamisele kuuluvad ülesanded

Esitamisele kuuluvad 2 ülesannet. Lisaks on 1 edasijõudnute ülesanne, mis on teise tunnitöö laienduseks.

Esimeses ülesandes on sinu rolliks olemasolevas programmis vaid funktsioonide sisud kirjutada. Selle programmi raames töötame vaid üksikute muutujatega.

Teises ülesandes tuleb kirjutada kogu programm juhendi põhjal

Ülesanne 1: Elektri hinna kalkulaator

Antud ülesandes on sinu eest juba kogu programmi loogika valmis tehtud. St kogu main()  funktsiooni sisu on juba valmis ja seda muuta ei ole põhjust.

Tegemata on jäetud aga enda loodavate (user-defined) funktsioonide sisud ning need on vastavalt asendatud kõik tagastama 0 väärtust (selleks, et programm kompileeruks). Sinu ülesandeks täita kõigi funktsioonide deklaratiivne osa (keha) vastavalt funktsioonile eelnevale kommentaarile.

Lae alla ülesande aluskood siit: 6_1_electricity_basecode.c

Nõuded
  • Ülesande lahendamist alusta baaskoodiga tutvumisest. Sinu lahendus peab olema ehitatud ette antud baaskoodile.
  • Sinu ülesandeks on kirjutada funktsioonide kehad seitsmele funktsioonile. Funktsiooni eesmärk on kirjeldatud selle ees kommentaarina.
  • main()  funktsiooni sisu ja koodi struktuuri muuta ei tohi. Soovitav on vältida ka funktsioonide ja muutujate ümbernimetamist.
Vihjeid ja soovitusi
  • Alusta tutvumist koodi ülesehitusest. Vaata kus on makrod, kus prototüübid, kus main() ja kus funktsioonid. Vaata kuidas main() funktsioonist teisi funktsioone välja kutsutakse, mis kaasa antakse jne. Ära muuda midagi alguses!
  • Üldine pilt selge, hakka järjest funktsioonide sisusid täitma.  Lahenda 1 funktsioon korraga, kompileeri ja testi enne kui järgmise juurde lähed!
  • Sisestuse funktsioonides on soovitatav struktuur do while tsükkel, mille sees on if lause veateate väljastamiseks.
  • Kõik ülejäänud funktsioonid on lahendatavad ühe reaga, asendades olemasoleva return 0  asemel õige valemi
  • Ettevaatust ühikutega. Erinevates kohtades on kord kasutusel vatt-tunnid, kord kilovatt-tunnid, kord megavatt-tunnid! Juhindu funktsiooni kommentaaridest.
  • VAT – value added tax tähendab käibemaksu (Eestis 20%)
  • Jooksev börsihind MWh kohta (enne makse) on leitav https://dashboard.elering.ee/et
  • Jooksvat börsihinda kWh kohta sentides koos maksudega näitab https://www.elektrikell.ee
Testimine
Test 1: veavaba sisend
Test 2: Vigane sisend

Ülesanne 2: massiivist tulemuste leidmine

Teise ülesande eesmärk on massiivist erinevate tulemuste leidmine vastavalt senistele teadmistele. Loodavad funktsioonid peavad olema universaalsed (ei sõltu massiivi pikkusest). Need on muuhulgas ka esimesed sageli kasutatavad funktsioonid sinu varasalve mida saad tulevikus kiirelt kasutusse võtta!

Nõuded
  • Loo programm, mis loeb kasutajalt 5 täisarvu. Arvud jäävad vahemikku -100 … 100
  • Trüki loetud massiiv enesekontrolliks välja.
  • Leia aritmeetiline keskmine ja kuva see kahe komakohaga
  • Leia ning kuva väikseim arv massiivis
  • Luba kasutajal sisestada otsitava numbri ning leiab ja kuvab kas see paikneb varasemalt sisestatud massiivis või mitte.
  • Funktsioonid (sh nende parameetrid ja tagastus) peavad vastama täpselt käesoleval leheküljel antud nõuetele (ptk “Ülesande samm-sammuline lahendusjuhend”)
Kondikava

Järgnevalt on soovitus ülesande lahenduse kondikavaks.

Ülesande samm-sammuline lahendusjuhend

Ülesande loomisel on täiendavad reeglid lisaks varasemalt õpitule.

  • Makrotena defineeritud konstandid mis võivad ülesandest ülesandesse erineda (nt massiivi pikkus, min ja max väärtused, maksude suurus) tuleb edastada funktsiooni parameetrina.  See ei kehti maagilistele numbritele, mis kunagi e muutu (nt elektroni mass, universaalne gaasikonstant, pi).
  • Tulemusi leidvatel funktsioonidel ei tohi olla kõrvalmõjusid (nt aritmeetiline keskmine, vähim arv, kas arv on funktsioonis). Tulemus tuleb tagastada main funktsiooni ja seal välja trükkida.  Leitud tulemuse väljatrükk funktsioonis endas on keelatud!
  • Kõrvalmõjud on lubatud ainult sisestuse ja väljastusega tegelevates funktsioonides (nt “ühe arvu sisestus” ja “massiivi väljastus”)
  • Globaalmuutujaid ei kasuta! Kõik muutujad peavad olema lokaalmuutujad, andmevahetus käib parameetrite ja tagastuse abil.

Lahenda programmi samm-sammu haaval. Testi igat funktsiooni pärast selle loomist enne edasi minemist. Funktsioonid on toodud selles järjekorras nagu soovitame neid luua antud ülesande tarbeks.

Luua tuleb kõik all kirjeldatud funktsioonid. Funktsioone võib olla enam kui see tundub otstarbekas. Meeldetuletuseks – funktsioonid on lühikesed ja lihtsad, millel reeglina puuduvad kõrvalmõjud ja mis teevad vaid ühte asja (ja teevad seda hästi).

 ➡ Funktsioon: ühe täisarvu sisestus

Kirjeldus: Loeb kasutajalt ühe täisarvu, mis peab asuma ettemääratud vahemikus. Vahemik antakse funktsiooni parameetritega seda välja kutsudes. Funktsioon ei tohi enne tagastada tulemust, kui kasutaja on sisestanud sobiliku väärtuse. Ebasobiliku numbri korral küsitakse sisestust uuesti.

Parameetrid:

  • Täisarv, millest väiksem ei tohi sisestus olla.
  • Täisarv, millest suurem ei tohi sisestus olla.

Tagastus: Täisarv, mis jääb vahemikku min ja max.

Kasutus: Programmi raames tuleb sul kahes kohas kasutajalt sisestusi küsida. Kasuta seda funktsiooni mõlemas neist kohtadest!

 ➡ Funktsioon: massiivi täitmine

Kirjeldus: Funktsiooni abil loetakse sisse n arvu ning salvestatakse need massiivi. Funktsioonis endas ühtegi scanf()  lauset olla ei tohi! Arvu lugemiseks kutsutakse välja eelnevalt tehtud funktsioon “ühe täisarvu sisestus”, tagastatav tulemus salvestatakse massiivi. Seda tehakse korduvalt tsüklis iga liikme lugemiseks.

Parameetrid:

  • Täisarvude massiiv –  täidetav massiiv.
  • Täisarv – massiivi liikmete arv.

Soovi korral võid lisada funktsiooni täiendavalt 2 parameetrit min ja max (loetavate väärtuste alam- ja ülempiir)

Tagastus: puudub.

 ➡ Funktsioon: massiivi väljatrükk

Kirjeldus: Funktsiooni abil trükitakse ekraanile selles sisalduvad väärtused.

Parameetrid:

  • Täisarvude massiiv – väljastatav massiiv.
  • Täisarv – massiivi liikmete arv.

Tagastus: puudub.

 ➡ Funktsioon: aritmeetiline keskmine

Kirjeldus: Funktsiooni abil leitakse massiivi liikmete aritmeetiline keskmine ning tagastatakse see.

Parameetrid:

  • Täisarvude massiiv – massiiv, mille väärtuste keskmist leitakse.
  • Täisarv – massiivi liikmete arv.

Tagastus: reaalarv – aritmeetiline keskmine.

 ➡ Funktsioon: vähim arv

Kirjeldus: Funktsiooni abil leitakse massiivi liikmete hulgast vähim väärtus ning tagastatakse see.

Parameetrid:

  • Täisarvude massiiv – massiiv, mille väärtuste hulgast vähimat leitakse.
  • Täisarv – massiivi liikmete arv.

Tagastus: täisarv – väikseim väärtus massiivis.

Testimine
Test 1: vigu ei esine
Test 2: vead sisendis

Edasijõudnute ülesanne 1: Massiivist väärtuse leidmine

Selle ülesande käigus tuleb luua täiendav funktsioon, mille raames kontrollitakse kas otsitav arv on massiivis või mitte.

Ülesande raames on lubatud kasutada kodeeritud täisarvu asemel tõeväärtust (boolean), kuid teemana jõuame selle juurde alles mõne nädala pärast.

Meeldetuletuseks:

  • Tagastades kodeeritud täisarvu hoidu maagilistest arvudest.
  • Funktsioonil ei tohi olla kõrvalmõjusid.
Funktsiooni kirjeldus

Kirjeldus: Funktsiooni abil kontrollitakse kas massiivis eksisteerib otsitav väärtus või mitte ning tagastatakse vastav täisarvuna kodeeritud väärtus.

Parameetrid:

  • Täisarvude massiiv – massiiv, mille väärtuste hulgast otsitavat leida tuleb.
  • Täisarv – massiivi liikmete arv.
  • Täisarv – massiivist otsitav väärtus.

Tagastus: täisarv – kas otsitav väärtus leiti või ei leitud.

Testimine

Edasijõudnute ülesanne 2: n-kordsed uude massiivi.

  • Kasutaja sisestab kordaja (positiivne täisarv). Korduvkasuta juba eksisteerivat funktsiooni!
  • Loo funktsioon, mille käigus koostatakse uus massiiv
    • Liikmeteks lisatakse algsest massiivist vaid sellised arvud, mille absoluutväärtus on n-kordne sisestatud kordajast. Uude massiivi lisatakse absoluutväärtused algsetest arvudest.
    • Funktsioonil ei tohi olla kõrvalmõju – st ta ei tohi väljastada ümberpaigutatud arve. Samuti ei tohi see ise välja kutsuda funktsiooni, mis seda teeks.
  • Trüki välja uue massiivi liikmed. Kasuta mõnda olemasolevat funktsiooni selleks.

E.g.: Input array (-5, 3, -12, 9, 22), multiplier (3), formed array(3, 12, 9)

Testimine

Pärast seda tundi 

  • Tead mis vahet on lokaal- ja globaalmuutujal.
  • Mõistad mis asi on funktsioon ja miks nende loomine oluline on
  • Mõistad, et oleme funktsioone kasutanud juba esimesest nädalast peale. Oleme kasutanud nii funktsioone, mis tagastavad väärtusi, kui ka neid, mis ei tagasta.
  • Mõistad, et me saame täpselt samasuguseid funktsioone ise luua ja oskad seda teha.
  • Mõistad järgmisi termineid:
    • Funktsiooni prototüüp
    • Funktsioon tagastuse tüüp
    • Funktsiooni argumendid
    • Funktsiooni parameetrid
    • Funktsiooni päis
    • Funktsiooni keha
  • Suudad luua korrektseid funktsioone
  • Suudad anda funktsioonidesse nii üksikuid väärtusi kui massiive
  • Suudad tagastada funktsioonist väärtusi
  • Suudad salvestada funktsiooni poolt tagastatud väärtuse
  • Suudad funktsioone korduvalt kasutada erinevate argumentidega
  • Suudad oma koodi tükeldada funktsioonideks
  • Omad lühikest loetelu universaalsetest funktsioonidest, mida sa saad tulevikus kasutada! See loetelu täieneb iga nädal!

Täiendav materjali

15. labor: Failid

Labori materjal

Esitamisele kuuluvad ülesanded

Selles laboris on 2 ülesannet, millest mõlemale on edasijõudnute ülesanded laiendusena.

Ülesanne 1: paaris/paaritu

Selle ülesande peamiseks eesmärgiks on harjutada mitme faili korraga käsitlemist ning selle korrektselt tegemist.

Nõuded
  • Sisendfailist loetakse teadmata kogus täisarve, mis on eraldatud tühiku või reavahetusega. Arve võib olla lõpmata palju.
    • Näiteks: 5 3 -6 0 25 955 -1024
  • Arvud jaotatakse lähtuvalt järgnevatele põhimõtetele:
    • Nulliga võrdsed või väiksemaid arve ignoreeritakse.
    • Positiivsed paarisarvud salvestatakse faili paaris.txt
    • Positiivsed paaritud arvud salvestatakse faili paaritud.txt
  • Jälgida tuleb elementaarseid failide käitlemise reegleid
    • Faili avamist kontrollitakse alati
    • Kui fail ei avane siis sellest teavitatakse kasutajat, sealjuures täpsustatakse ka milline fail ei avanenud.
    • Failid sulgetakse enne programmi lõppu
  • Kui sisendfailis on vales formaadis sisend peab programm töö katkestama.
    • Näiteks 9 -5 hey 14
Hoiatused ja vihjed!
  • Ole väga ettevaatlik lõpmatute tsüklitega olukorras kus toimub ka faili kirjutamine – võid oma kettaruumi mõne sekundiga täis kirjutada.
  • Jäta vähemalt testimise ajaks ekraanile väljatrükk iga loetud numbri kohta ning millisesse faili see kirjutatakse. Sedasi on lihtsam aru saada kui midagi läheb valesti ja saad kiiresti katkestada programmi ( ctrl+c ) kui tekib lõpmatu tsükkel).
  • Kui esimene fail õnnestus avada, kuid teine mitte, siis enne väljumist tuleb esimene kinni panna!
Edasijõudnute ülesanne 1: statistikute leidmine

Leia järgnevad statistikud:

  • Täisarvude summa ja aritmeetiline keskmine
  • Vähim ja suurim arv
  • Kõik tulemused tuleb leida terve sisendfaili ulatuses olenemata arvust (sh negatiivsetest arvudest!).
  • Korduv faili lugemine pole lubatud selle ülesande lahendamiseks.
  • Programm peab jätkuvalt töötama lõpmata paljude arvudega.
Edasijõudnute ülesanne 2: käsurea argumendid

Lisa programmile käsurea argumentide tugi. Muuda programmi järgnevalt

  • Sisendfaili nimetus loetakse alati käsurealt.
    • Kui faili nimetust ei anta kuvatakse veateade ning programm sulgeb end
    • Faili nimetus on alati esimene argument programmile
  • Verbose ehk jutukas
    • Programm peab tuvastama argumendina -v  ehk verbose
    • Programm kuvab iga faili avamise järel mis fail avati (nimeliselt)
    • Programm kuvab iga sisendist loetud numbri ning millisesse väljundfaili see kirjutati
    • Programm kuvab iga faili sulgemise
    • Kui verbose ei ole aktiivne, ei tohi programm ühtegi rida teksti kuvada (välja arvatud veateated ja edasijõudnute ülesanne 1 väljund)

Mõlemad argumendid on laialtlevinud praktikad käsureaprogrammide puhul, kuid leiavad sageli kasutamist ka graafilistes programmides.

Programmi käivitamise näited mis peavad olema toetatud:

  • ./parity input_nums.txt
  • ./parity input_nums.txt -v

Ülesanne 2: Hoiatustrahvide menetlemine

Ülesande eesmärgiks on luua programm, mis menetleb kiiruskaamerate poolt mõõdetud kiiruseületamisi.

Taustteave

Ülesanne on koostatud avaliku informatsiooni põhjal

Trahvi koostamise põhimõtted
  • Seadme mõõtemääramatus on 4 km/h (50 – 90 km/h alad).
  • Menetlust alustatakse, kui kiirust ületati vähemalt 3 km/h.
  • Iga piirkiirust ületatud km/h eest tuleb tasuda 5€.
  • Maksimaalne trahvisumma on 300€.
  • Kui lubatud kiirust ületati 50 km/h tuleb alustada üldmenetlust.
  • Näiteks: sõites 90 km/h alas kaamerasse 99 km/h tuleb määrata hoiatustrahviks 25€.
Sisendfail

Lae alla testandmetega sisendfail: 14_2_speeds.txt

Sisendfailis on üks mõõtetulemus rea kohta. Sisendfaili struktuur: <auto registreerimisnumber> <mõõdetud kiirus> <piirkiirus>

  • Auto registreerimismärk – kuni 9 tähemärki pikk sõne
  • Mõõdetud kiirus – positiivne täisarv
  • Piirkiirus – positiivne täisarv.
Loodavad väljundfailid

Programmi tulemusena luuakse 2 väljundfaili – hoiatustrahvid ja üldmenetluse teated.

Esimese loodava väljundfaili sisuks on hoiatustrahvid. St sinna faili tohib kirjutada vaid trahviteatised, mis tuleks sõidukiomanikel tasuda. Iga hoiatustrahv kirjutatakse eraldi reale. Iga rea kohta on  kolm andmevälja:

  • Numbrimärk
  • Kiiruseületus ilma mõõtemääramatuseta (mitu km/h üle piirkiiruse sõideti)
  • Trahvisumma (kiiruseületamisele vastav hoiatustrahv)

Oodatav tulemus:

Teise loodava väljundfaili sisuks on üldmenetluse teated. St sinna tohib vaid kirjutada need, kelle suhtes alustatakse üldmenetlust. Üldmenetluse teated kirjutatakse järgneva formaadiga:

Oodatav tulemus:

Edasijõudnute ülesanne: seadistatavus

Kuna seadused on pidevas muutumises, siis trahvimäärade koostamiseks kasutatavad väärtused peavad olema lihtsasti seadistatavad. Mõtle välja kõige lihtsam lahendus järgnevate nõuete realiseerimiseks

1. Kiiruseületamise menetlemine peab olema seadistatav:

  • Iga ületatud km/h eest makstav summa (nt 3€, 5€, 10€)
  • Maksimaalne hoiatustrahvi summa (nt 100€, 190€, 300€)
  • Üldmenetluse alustamiseks vajalik kiiruseületus (nt 40 km/h, 61 km/h, 100 km/h)

2. Seadistamine peab olema lihtne aga igapäevaelus nähtamatu

Leia sobiv lahendus programmi seadistatavaks muutmiseks lähtuvalt järgnevatest nõuetest:

  • Seadistusvõimaluse lisamine ei tohi muuta programmi igapäevast kasutamist aegavõtvamaks.
    Mõte: Igapäevasel kasutamisel ei soovi politseiametnik aega raisata asjade ümberseadistamisega ega isegi nt olemasoleva seadistuse kinnitamisega.
  • Seadistusvõimaluse muudatus peab kehtima senikaua kuniks seda uuesti tehakse.
    Mõte: Olles näiteks pärast seadusemuudatust tarkvara ära seadistanud uutele väärtustele ei soovi sa seda iga päev uuesti teha.
  • Seadistuste muutmine ei tohi vajada programmi ümberkompileerimist.
    Mõte: Keegi ei kujutaks ette, et politseiametnik hakkab programme ümber kompileerima keset tööpäeva.

Pärast seda tundi

  • peaksid oskama faile avada ja sulgeda
  • peaksid oskama kontrollida faili avanemist
  • teadma mis vahet on erinevatel faili avamise režiimidel ning kuidas need käituvad vastavalt kas fail eksisteerib või ei eksisteeri
  • teadma mis olukordades failid ei avane kui neid avada lugemiseks või kirjutamiseks
  • teadma erinevaid failide adresseerimise võimalusi
  • teadma mida tähendab failide juures puhverdamine ning mis ohte see võib kaasa tuua
  • oskama faile lugeda ja kirjutada

Täiendav materjal

13. labor: Sõned

Labori materjal

Esitamisele kuuluvad ülesanded

Selles tunnis on 2 ülesannet, millest esimeses õpime tundma string.h teeki ning teises manipuleerime tähemärke käsitsi.

Ülesanne 1: string.h teegiga tutvumine

Selle ülesande käigus loome ühe programmi, mille käigus tutvume peamiselt erinevate string.h teegis olevate funktsioonidega.

Nõuded
  • Programmi koostamiseks liigu samm-sammult juhendis antud järjekorras.
  • Programmi käivitades küsitakse kasutajalt parooli. Enne õige parooli sisestamist ei tohi programm edasi minna.
  • Kasutajalt loetakse lause. Programm kuvab mitu tähemärki lauses oli (sh tühikud, kirjavahemärgid).
  • Kasutajalt loetakse otsingufraas. Seejärel väljastatakse kas eelnevalt sisestatud lauses see fraas esines või mite (jah/ei vastus).
  • Kasutajalt küsitakse 2 sõna, mida kasutatakse lause moodustamisel.
    • Sõnade tüübid võid ise valida (nt nimi, ese, omadussõna, tegusõna, …)
    • Kleebi kasutaja poolt sisestatud sõnad kokku, lisades enda poolt täiendavaid sõnu moodustamaks vähemalt neljast sõnast koosneva lihtlause.
    • Üks kasutaja sisestatud sõnadest peab olema selle lauses esimene sõna.
    • Moodustatav lause tuleb salvestada täiesti uude tähemärgimassiivi, mis peab mahutama selle lause ka siis, kui loetud 2 sõna olid maksimaalse lubatud pikkusega.
Abifunktsioon

Kui sul tekib ühel või teisel hetkel probleeme aru saamisega mis sul tekstimassiivi sisuna salvestatud on, siis võid seda funktsiooni kasutada. Antud funktsioon trükib välja tervikliku sõne, misjärel trükitakse kõik tähemärgid ja selle vastavad ASCII tabeli täisarvulised väärtused. Nii on hea lihtne tuvastada kui näiteks mõni reavahetus või muu imelik sümbol jääb massiivi sisse.

Juhend
1. samm: kasutaja sisestuse lugemine

Esimese sammu teeme tunnis koos läbi! Selle käigus loome me 2 vajalikku funktsiooni oma programmi.

Alustame esimesest mida kasutame sõne lugemiseks. Lahenduses on oluline, et me suudaksime lugeda mitmetest sõnadest koosnevaid sõnesid ehk tühik ei tohiks meil lugemist ära lõpetada! Selleks on mitmeid viise, kuid meie läheneme ülesandele kasutades funktsiooni fgets() . Soovi korral võid ise teist teed minna.

Funktsiooni fgets()  eripäradeks on, et ta on mõeldud lugemaks failist. Küll aga kõik asjad on failid, sh ka klaviatuurilt tulev andmevoog, seega saame kasutada failina stdin  nimelist faili. Teine keerukus antud funktsiooni juures on see, et ta vajab endale pikkust palju tohib lugeda – see on tegelikult ohutuse tagamiseks, et puhvri pikkusest üle ei loetaks. Kolmas ja kõige probleemsem on see, et kui me vajutame klaviatuurilt enter klahvi, siis see reavahetus \n  salvestatakse samuti sinna massiivi.

Lähenemises kasutame põhimõtet, et loome funktsioonidele wrapperid ehk ümbritseme need täiendavate lausetega, mis funktsiooni kasutamise meeldivamaks või mugavamaks muudavad meie jaoks.

Meie ümbrisel on vaja kahte sisendit – sõnet ehk tähemärgimassiivi kuhu loetava teksti salvestame ning kui suur see tekstimassiiv loomise hetkel oli, et me lubatud pikkusest üle ei kirjutaks ja programmi rünnata sedasi ei lubaks.

Antud lahenduses olen jätnud kolme kohta küsimärgid sisse, kus pead ise lüngad täitma! Vihjeks: kui loetud stringi pikkus on 10 tähemärki, siis indeksiga 8 on meie jaoks viimane oluline tähemärk mille kasutaja sisestas. Sellele järgneb meile ebasoovitav reavahetus, millest peame lahti saada, asendades selle sõne lõpu sümboliga.

Vajadusel kasuta varasemalt välja toodud abifunktsiooni!

Selleks, et funktsioon ka kompileeruks olen need 2 täiendavalt vajalikku rida välja kommenteerinud. Olles küsimärgid asendanud kommenteeri need sisse.

Kui lugemine on valmis, loome järgmise ümbrise oma vastloodud GetString()  funktsioonile. Nii saame mugavalt sisestust küsida!

Nüüd kui soovime mõnda sõnet lugeda, saame oma väljakutse luua üsna mugavalt. Näiteks kui meil on tähemärgimassiiv sentence[]  mille pikkus on defineeritud makroga MAX_STR , saame väljakutse luua

2. samm: lause lugemine ja selle pikkus

Loe kasutajalt sisse lause. Seejärel leia ja väljasta sisestatud lause pikkus.

3. samm: fraasi otsimine

Lisa programmi funktsioon, milles küsitakse kasutajalt otsingufraas. Programm väljastab seepeale kas see fraas eksisteeris varasemalt sisestatud lauses või mitte.

Jah-ei vastuseks piisab kui kontrollida tagastust järgneval kujul

4. samm: parooli küsimine

Lisa programmi funktsioon, mis küsib kasutajalt parooli. Näiteks:

Parooli küsimine peab olema tsüklis ja küsima kasutajalt parooli senikaua, kuniks kasutaja sisestab korrektse parooli. Parooli kontroll peab olema tõstutundlik (st suuri ja väiketähti ei võrdsustata). Soovi korral võid panna programmi vale parooli puhul vihjeid andma või end sulgema pärast korduvalt parooli valesti sisestamist.

5. samm: lause moodustamine

Lisa programmi funktsioon, mille käigus moodustad lihtlause. Kuna funktsioonile meil head sisendit ega tagastust anda ei ole, võiksid alustada funktsiooni sedasi (void-void funktsioonid on erandlikud ja enamasti tuleb neid vältida!):

Mõttekoht: kui pikk peaks olema sentence  massiivi pikkus, et see mahutaks halvimal juhul ära mõlemad kasutaja sisestatud sõnad ning sinu lisatavad sõnad, tühikud ja kirjavahemärgid, et moodustada lauset? Suurus võib olla liigkaudne aga peab olema piisav!

Edasi mõtle välja millist lauset moodustada soovid. Oluline on, et selles lauses oleks kaks lünka, kuhu kasutaja sisestab enda soovitud sõnad (ise otsustad millised – nt inimese nimi, ese, nimisõna, tegusõna, …). Üks nendest sõnadest peab olema lause esimene sõna, teise asukoht on sinu enda otsustada. Näiteks <sõna1> on <sõna2> nimi! .

Olles kasutajalt sõnad pärinud ja programmi sisse lugenud tuleb sul need sõnad lauseks kokku kleepida. Kokku kleebitav lause peab olema salvestatud täiesti uude tühja tähemärgimassiivi. Oluline on arvestada, et mis iganes kasutaja sisestab (lubatud pikkuste raames) peab ära mahtuma sinna koostatavasse massiivi ka sellisel juhul, kui kasutaja otsustas maksimaalselt pikad sõnad sisestada.

Näide
Lisaülesanne: Tähtede loendus

Loo käsitsi uus loendamise funktsioon ning väljasta statistika

  • Loenda ja kuva mitu tähte [a-zA-Z] oli lauses. Ära loenda kirjavahemärke, tühikuid jne.
  • Leia ja kuva mitu protsenti kogu lausest moodustasid tühikud, kirjavahemärgid ja muud sümbolid.
  • Näita protsent ühe komakohaga.

Näide

Ülesanne 2: CSV-st meiliaadresside genereerimine

Selle ülesande eesmärk on sulle tutvustada laialtlevinud andmeformaati CSV (comma separated value). Ülesande lahendamise käigus saad harjutada üksikute tähemärkide tuvastamist ja töötlemist.

Lae alla ülesande aluskood: 12_2_csv_starter.c

CSV formaat

CSV on struktuursete andmete hoiustamise formaat, kus iga andmeväli on eraldatud eelnevast ja järgnevast komaga. Tegu on tõenäoliselt kõige levinuma andmete varundamiseks ja hoiustamiseks  kasutatava formaadiga väljaspool andmebaasisüsteeme. Tema peamisteks eelisteks on lihtne struktuur ning sellest tingitult on CSV toetatud praktiliselt kõigis rakendustes, mis vähekegi andmetega töötlevad.

Kõige lihtsamal kujul nagu öeldud on kõik väljad eraldatud üksteisest komaga. Näiteks:

Täpselt sellise keerukusega andmeid vaatame ka selles tunnitöös. Nägemaks keerulisemaid formaate ja reegleid kuidas hoiustada väljasid, mis peavad sisaldama komasid, jutumärke ning kuidas lisada pealkirju võid lugeda siit: https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules

Nõuded
  • Ülesande lahendus on ehitatud antud aluskoodile
  • Programm loob igale aluskoodis antud inimesele e-postiaadressi.
    • e-postiaadressi nimeosa koosneb kolmest eesnimetähest ja kolmest perenimetähest.
    • Nimeosale järgneb sinu valitud domeen.
    • E-postiaadressi nimi ja domeen peavad koosnema vaid väiketähtedest.
    • E-postiaadress tuleb salvestada terviklikult tekstimassiivi (loo uus muutuja seal kus vaja) ja väljastada selle kaudu. Jooksvalt tähemärkhaaval väljastus pole lubatud.
  • Programm väljastab:
    • Inimese täisnime. Eesnime ja perenime osa peavad olema eraldatud tühikuga
    • Genereeritud e-postiaadressi.
  • Aluskoodis juba olevat koodi ülesande lahendamiseks muuta ei tohi ilma juhendaja poolse nõusolekuta. Sinu poolt kirjutatava lahenduse alguspunkt peaks asuma  ProcessPerson()   funktsiooni sees. Soovi korral võid julgelt funktsioone juurde lisada.
Näide
Vihjed
  • Teades koma asukohta, tead ka mis indeksilt algab perenime esimene täht
  • ASCII suur- ja väiketäht erinevad üksteisest ühe biti võtta, mille järgu väärtuseks on 32 (nt A 65, a 97)
  • Kõik toimingud peale e-mailiaadressi lõpu lisamise on kõige lihtsam teha selles ülesandes tähemärk-haaval. Saab ka kasutada string.h  teegi funktsioone, kuid need võivad olla asjatult keerukad.
  • Kõige tüüpilisem viga selles ülesandes on unustada sõnele null-baidi ehk terminaatori lõppu lisamist pärast nimeosa koostamist!
Lisaülesanne 1: lühikesed nimed

Muuda oma e-postiaadresside genereerimise algoritmi sedasi, et see tuleks toime ka lühemate nimede puhul.

Näiteks: Ly Kask -> lykask@ttu.ee

Lisaülesanne 2: unikaalsed e-postiaadressid

Muuda oma e-postiaadresside genereerimise algoritmi sedasi, et see genereeriks unikaalseid postiaadresse ka siis kui nimel on sarnane algus.

Muuda oma data massiiv järgnevaks:

Nõuded

  • Loodavad e-postiaadressid peavad olema unikaalsed
  • Aadressi nimeosa peab jätkuvalt olema 6 tähemärki
  • Aadressid peavad jätkuvalt viitama nime omanikule nii palju kui võimalik
  • Täpne algoritm ja seega saavutatav nimekuju on sinu enda valida. Põhjenda valitud lahendust kaitsmisel.

Pärast tundi peaksid

  • Teadma, et tähemärkide jaoks kasutatakse erinevaid kodeeringuid, muuhulgas ASCII ja Unicode
  • Teadma mis on ASCII tabel ning kuidas seda kasutada.
  • Teadma kuidas töötavad sõned C keeles.
  • Teadma kuidas lõpetatakse sõnet C keeles (null-terminaator/null-bait).
  • Seostama C keelseid sõnesid baidijadadega.
  • Teadma mis on CSV.
  • Oskama kasutada string.h teeki sõnede manipuleerimiseks.
  • Oskama ka ise kirjutada sõnede manipulatsioone (tähemärkhaaval lähenemine).
  • Teadma mis asi on puhvri ületäitumine ning selle kaudu tehtavatest rünnakutest.

Täiendav materjal

8. Voo suunamine ja pseudojuhuarvud

Labori materjal

Esitamisele kuuluvad ülesanded

Selles laboris on kaks ülesannet, millest mõlemale on laiendusena pakutud välja lisaülesanne.

Ülesanne 1: kuupäeva kontroll

Ülesande eesmärgiks on tuvastada kas sisestatud kuupäev on tõene või vigane. Ülesande raames tutvume ka voo suunamisega.

Lae alla ülesande aluskood: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_1_date_base.c

Nõuded
  • Programm kuvab iga kuupäeva puhul kas tegu on reaalse või vigase kuupäeva.
  • Aastate vahemik on piiratud 1900 – 2099
  • Programmis on rakendatud liigaasta kontroll
  • Maksimaalselt töötleb 100 kuupäeva
  • Kuupäevad vastavad kõik formaadile DDMMYYYY .
  • Baasülesande raames tuleb lahendada funktsioonid sellisel kujul nagu nad antud on.  Kohustuslike funktsioonide loetelu ja kommentaarid leiad aluskoodist.
  • Programmi esitades pead seda tegema kasutades sisendvoo ümbersuunamist. Sisendiks on fail, mis sisaldab endas sellel lehel antud testkuupäevasid.
Algoritm

NB! Algoritm näitab meile üldisemat ideed ülesande lahenduskäigust ning on eelkõige informatiivse väärtusega. Algoritmis ei kajastu kuidas võiks toimida andmevahetus funktsioonidega. Samuti on funktsioonide kasutamisest tulenevalt mõningad järjestusest teistmoodi.

Samm-sammuline lahendamisjuhend

Alususeks peame tegema andmefaili. Sinna kirjutame samad andmed, mida muidu trükiksime klaviatuurilt iga kord programmi testides. Teisisõnu kirjutame oma testandmed ühekordselt ära ja hiljem lihtsustame oma testimist sedasi. Mõnel ülesandel võib taolisi testfaile olla mitu, mõnel piisab ühest.

Lähtefaili kirjutades tuleks arvestada kõikvõimalike erinevate juhtudega,  mis programmis esineda võivad. Kindlasti tuleb testida nii sobilike kui ka mittesobivaid kuupäevi. Näiteks võib siin olla tavapäraseid kuupäevi – 11. detsember 1981, kuid samuti ka ebareaalseid kuupäevi – 51. detsember, kuu nr 22 jne. Eriti olulised on piirjuhud – nt 29. veebruar liigaastal ja tavapärasel aastal. Järgnevalt on välja pakutud üks võimalik loetelu kuupäevi (võid julgelt kuupäevi lisada loetelu lõppu, kuid need peavad kindlasti sisalduma testis).

Siin on sinu testsisend. Salvesta see tekstifailina samasse kausta kuhu oma programmi paned!

Järgmiseks oleks meil vaja programmi, mis neid kontrollima hakkaks.

Nüüd hakkame töötama ette antud aluskoodiga. Esimesed kaks funktsiooni teeme tunnis koos ära! Kui tunnis polnud, vaata loengusalvestust!

Nüüd peaks meil olema 2 faili, mõlemad samas kaustas:

  1. Programmikood (nt date.c )
  2. Tekstifail sisendandmetega (nt input või input.txt )

Järgmisena on meil vaja programmi. Üks valik programmi loomiseks on see kompileerida läbi Geany või mõne teise rakenduse mida oled senimaani kasutanud. Võid seda julgelt teha kui end sedasi mugavamalt tunned. Ära vaid unusta iga kord uuesti kompileerimast pärast muudatusi!

Ava mind, et näha kuidas seda teha käsurealt

Kompileerida võid ka käsurealt. Täpselt sama asi juhtub tegelikult kui nt Geany sees vajutad build nuppu. Selleks on üldine struktuur kompilaatori_nimi -o programmi_nimi koodifaili_nimi.c . Oluline on, et -o järel on alati soovitav programmi nimi (väljund). Kõige lõppu paneme me aga oma programmi koodi sisaldava faili nime. Lisaks kasutame tavaliselt täiendavaid lippusid, et meile ka rohkem veateateid kuvatakse. Näiteks -Wall  ja -Wextra .

Nüüd paneme selle kõik kokku. Olles saanud käsuakna õigesse kausta kus asuvad su teised failid saad teha järgmist:

gcc -o date -Wall -Wextra date.c

Selle reaga kompileeritakse lähtekoodi fail date.c  programmiks nimega date .

Veendume, et failid on kõik seal, kus peaks kasutades käsku ls -l :

Kui varem oli meil 2 faili, siis nüüd peaks neid olema 3:

  • date  – nn binaarfail ehk programm, mis loodi lähtekoodi kompileerimise tulemusena. Käivitatav!
  • date.c  – lähtekoodi fail. Siia kirjutame me tekstiredaktoriga koodi, ei ole käivitatav programmina!
  • input.txt  – tekstifail, mis sisaldab kuupäevi ehk testandmed.

Nüüd käivitame programmi sedasi, et klaviatuurilt trükkimise asemel loetakse andmed ette söödetud failist (kasutades voo ümbersuunamist). Selleks saame kasutada järgmist struktuuri, asendades failid õigete nimedega: ./programminimi < andmefailinimi

./programminimi – sedasi saad programmi käima Linuxis käsurealt
< – tähistab, et programmi klaviatuurilt tulevad sisestused juhitakse ümber
andmefailinimi – siit hakatakse lugema mida programmile ette sööta ehk siis kust sisestus tuleb

Siin lõppeb tunnis koos tehtav osa ning algab iseseisev töö. Selleks hetkeks peaks programmi väljund olema järgmine

Testimine: valmislahendus

Pärast programmi valmimist peaks su väljund nägema välja samasugune nagu siin.

Ülesanne 2: loto

Lae alla ülesande aluskood:

Nõuded
  • Tunnitöö tuleb ehitada ette antud aluskoodile.  Aluskood on sulle antud ning sisaldab juba funktsioonide loetelu funktsioonidest koos kommentaaridega mis tuleb sul realiseerida ja kasutusele võtta.
  • Lotonumbrid genereeritakse vahemikus 1 … 25 (otspunktid kaasaarvatud).
  • Kasutajalt küsitakse 6 arvu (lotonumbrid).
  • Programm genereerib juhuarvudena 10 arvu (võidunumbrid).
  • Programm kuvab genereeritud võidunumbrid
  • Kontrolli ja näita mitu ja millised numbrid kattusid.
    • Baasülesandes pole nõutud numbrite unikaalsus
    • Iga lotonumber saab kattuda võidunumbriga vaid ühel korral.
  • Kui kõik numbrid kattusid, õnnitle peavõidu korral. Kui ükski ei kattunud, avalda kaastunnet.
Testimine

NB! Kuna loterii nagu nimigi ütleb on juhuslik, siis selle testimisel tuleks juhuarvu seeme (srand funktsiooni argument) määrata konstandiks. Genereeri ühe korral lototroni numbrid ära ja jäta need meelde, et saaksid testi tulemusi kergelt korrata!

Test 1: Juhuslikud arvud, mõni võidunumber, sisestus OK.

Test 2: Võidunumbrid puuduvad

Test 3: Jackpot

Test 4: Vigane sisestus

Test 5: Iga number võidab vaid korra (absurdsed olukorrad – sanity check)

Antud testis teeme muudatuse oma lähtenõuetes, et testida mitu korda üks lotonumber võita saab. Kaine mõistus ütleb, et iga number saab võita vaid korra.

NB! See test töötab selliselt vaid siis kui unikaalsuse nõue ei ole täidetud (st pole tehtud lisaülesanne). Korduvad numbrid on seega lubatud.

Antud testi juures saame jälgida kusjuures kahte erinevat asja

  1. Jälgi võitude arvu! St Matched 6 out of 6!)
  2. Jälgi lototroni genereeritud numbreid. Need tohivad olla vaid ühed! (0 või 2 esinemine tähendab, et sul on viga juharvude valemi koostamisel!)
Märkus: Tunnitöö baasülesandes vaatleme vai lihtsalt juhtu, kus kasutaja arv saab võita ühekordselt. Näiteks kui kasutaja sisestab numbrid “1, 1, 1, 1, 1, 1” ja lototron genereerib “1, 2, 3, 4, 5, 6, 7, 8, 9, 10”, siis baasülesande raames piisab, kui loeme, et iga kokku tuli 6 tabamust. Kui aga kasutaja numbrid oleksid “1, 2, 3, 4, 5, 6” ja lototron genereeriks “1, 1, 1, 1, 1, 1, 1, 1, 1, 1”, siis oleks olnud vaid 1 tabamus.

Lisaülesanne 1: mittekorrektse kuupäeva põhjendus

Algse lahenduse puudujäägiks oli ebaselgus miks üks või teine kuupäev ei valideerunud. Täiendame oma programmi sedasi, et ka põhjus oleks arusaadav.

Nõuded
  • Laienda oma programmi nii, et programm põhjendaks miks kuupäev reaalseks ei osutu
  • Minimaalselt pead eristama
    • Ebasobivat aasta väärtust
    • Ebasobivat kuu väärtust
    • Ebasobivat päevade arvu, eristades sealjuures väiksemat ja suuremat kui lubatud väärtust
    • Mitte-liigaastal olevat 29ndat veebruari
  • Lahenduses võid lisada täiendavaid funktsioone ja muuta mõistuse piires ka olemasolevat programmi struktuuri.
  • Meeldetuletus! Väldi maagilisi arve!
Testimine

Lisaülesanne 2: lototronile unikaalsed numbrid

Selle ülesande eesmärk on muuta ülesanne täisväärtuslikuks. Selleks on meil vaja lahendada vaid üks funktsioon FindMatchCount()  ning seda õigetes kohtades kasutusele võtta.

Nõuded
  • Kasutaja poolt sisestatavatele numbritele tuleb rakendada unikaalsuse nõue. Kui kasutaja sisestab korduva numbri, tuleb see sama number uuesti küsida.
  • Lototronile tuleb rakendada unikaalsuse nõue. Lototroni poolt genereeritavad võidunumbrid ei tohi korduda.
  • Lahenduse käigus ei tohiks muuta GetUserNumbInRange()  ja GenerateRandomNum()  funktsioone, otsi selleks sobilikum koht.
  • Kommenteeri sisse ja lahenda ära funktsioon CheckIfNumInArray() . Võta see funktsioon kasutusele kolmes kohas
    1. Kasutaja lotonumbrite unikaalsuse kontrolliks
    2. Lototroni genereeritud võidunumbrite unikaalsuse kontrolliks
    3. Kasutaja ja lotoarvude kattuvuse leidmise funktsioonis FindMatchCount()
Testimine

Test 1: Kontrollime unikaalsuse nõuet kasutajale

NB! Kontrolli kindlasti kasutades sama jada!

Test 2: Kontrollime unikaalsuse töötamist lototroni poolt

Selleks, et kontrollida lototroni tööd peame me jällegi manipuleerima konstante.

Selle testiga on meil arvuti poolt genereeritud numbrite arv täpselt sama suur kui maksimaalne unikaalsete numbrite arv. St kõik numbrid 1 – 10 peavad saama genereeritud ning ükski neist korduda ei tohi.

Mõtle ja vasta ka küsimusele mis juhtuks kui oleksime konstandi pannud 9 peale?

Pärast tundi peaksid

  • Teadma millised standardvood eksisteerivad
  • Oskama kasutada voo suunamist erinevatel platvormidel
  • Oskama käivitada enda kompileeritud programme Linuxi käsurealt
  • Oskama kasutada tõeväärtusi (boolean andmetüüp)
  • Oskama tükeldada sisestust vajadusel tähemärkhaaval
  • Oskama kasutada scanf poolt taastatavat väärtust
  • Oskama kasutada üherealisi tingimuslauseid ja tsükleid
  • Oskama genereerida pseudojuhuarve
    • .. pannes need alati algama samast arvust
    • .. pannes need kellaajast sõltuvaks
  • Teadma mis vahet on pseudojuhuarvul ja juhuarvul
  • Oskama piirata juhuarvude genereerimise vahemikku
  • Teadma mis on ning kuidas töötab UNIXi kellaaeg, sh mis tähtsus on 1. jaanuaril 1970.

Täiendav materjal

10. labor: menüü-programm

Teooriat ja meeldetuletusi

Tähemärk, sõne ja väljastusfunktsioonid

Kuigi sõnede juurde tuleme alles mõne nädala pärast võime mõnda omadust ikkagi vaadata.

Sõne (string) tähendab järjestatud tähemärkide jada. St selleks võib olla arusaadav sõna või lause, kuid võib olla ka arusaamatu erinevate sümbolite jada. Sõned on alati jutumärkide vahel.

Näited:

    • "a"
    • "Hello!"
    • "I do wish we could chat longer, but I'm having an old friend for dinner."
    • "lFRD=)m+0FDj2"

Üksikut tähemärki hoiame aga ülakomade vahel. Sõne koosneb sellistest tähemärkidest. NB! Kaldkriipsuga hakkavad erisümbolid (escape sequence) ja neid loetakse üheks tähemärgiks (nt \n  on üks tähemärk arvuti mälus).

Näited:

    • 'a'
    • 'y'
    • '\n'
    • '\t'

Funktsioonid mida saame kasutada teksti väljastamiseks

  • printf()  ehk print formatted. Tegu on kõige keerukamaga seniõpitutest, mille abil saame trükkida kujundatud teksti, mille abil saame ka kõiksugu muutujate sisu väljastada. Reavahetus käib käsitsi!
    Näiteks: printf("Hello, %s!\n", name);
  • puts()  ehk put string. Tegu on lihtsa funktsiooniga mis on mõeldud ühe tekstilõigu kuvamiseks. See ei toeta keerukaid formaate ega muutujatest teksti väljastamist. Reavahetus lisatakse automaatselt.
    Näiteks: puts("Hello, user!");
  • putchar()  ehk put character. See on kõige lihtsam funktsioon neist kõigist. Selle abil saab väljastada vaid ühe tähemärgi. Seda on mugav kasutada nt reavahetuse trükkimiseks.
    Näiteks: putchar('\n');

Massiivi edastamine funktsiooni

Massiive alamfunktsioonidesse edastades andsime edasi viite originaalile – st me saame edastatud massiivi muuta ilma tagastamata ja olenemata kohast.

Reeglina tuleb alati massiiviga koos edastada selle kõigi dimensioonide suurused. Pärast funktsiooni edastamist neid suurusi välja arvutada enam ei ole võimalik! Erandiks on sõned (string), millest räägime tulevikus.

Mõned eripärad edastamisel

  • Kui soovid edastada tervet massiivi, olenemata selle dimensioonide arvust, täpsustame vaid selle massiivi nime Func(numbers);
  • Kui soovid 1-dimensioonilisest massiivist int numbers[N];  edastada vaid ühe väärtuse, täpsustame selle indeksi Func(numbers[2]); . Funktsioonis käsitle seda ühte arvu  Func(int val);
  • Kui soovid 2-dimensioonilisest massiivist ( int numbers[N][M];  edastada rea alguse, täpsustame selle indeksi ja pikkuse Func(numbers[2], M); . Funktsioonis käsitle seda kui 1-dimensioonilist massiivi  Func(int numbs[], int n);
  • Kui soovid 2-dimensioonilisest massiivist int numbers[N][M];  edastada vaid ühe väärtuse, täpsustame selle indeksi Func(numbers[2][1]);

Kahe arvu omavahel vahetamine massiivis

Vahetamaks kahte arvu sobib lahenduseks mullsorteerimise tunnist õpitud vahetamise idee kasutades abimuutujat

Märkus: isegi kui soovid vahetada kahe rea või veeru väärtusi on ikkagi vaja vaid ühte muutujat.

Massiivi kasutamine abimuutuja asemel on mõistlik vaid paralleeltöötlust toetavatele protsessoritele programme kirjutades. Sellised protsessorid põhinevad SIMD (sing-instruction-multiple-data) arhitektuuril – näiteks graafikakaardid (GPU – graphics processing unit).

Massiivide algväärtustamine nulliks

Terve massiivi algväärtustamiseks nulliks paneme soovitud konstandi loogeliste sulgude vahele

Kui tegu on 2-dimensioonilise massiiviga, kasutame kahte komplekti loogelisi sulge.

Esitamisele kuuluvad ülesanded

Selles tunnis tegeleme programmiga, mis töötab senikaua kuniks kasutaja soovib sellest väljuda. Programmi raames tegeleme maatriksi manipuleerimisega.

Alusta näidisprogrammiga tutvumisest, misjärel mine edasi ülesande lahendamise kallale.

Tunnitöö näidisprogramm

Sulle on antud tänasest tunnitööst näidisprogramm. See on antud kompileeritud kujul, st saad selle käivitada ja testida milline selle lõpptulemus peaks välja nägema. Sinu loodav programm peaks lõpuks töötama sarnaselt.

Mõlemad näidisprogrammid on kompileeritud x86-64 arhitektuurile. Garanteeritud töötavad mõlemad laboriarvutitel, kuid peaksid ka töötama enamikel isiklikel arvutitel. Probleeme võib tekkida ARM protsessoritega arvutitel ilma x84-64 emulatsiooni kasutamata.

NB! Linuxil kasutamiseks pead andma failile käivitamisõigused (turvalisus ennekõike!). Õiguste muutmine on ühekordne tegevus. Selleks toimi nii:

See lisab (chmod – change mode) kasutajale (u – user) õigused programmi käivitada (x – execute). Pärast seda tohid programmi käivitada tavapäraselt, st ./program_name

Kirjeldus

Tänane tunnitöö on jaotatud kaheks eraldi hinnatavaks osaks, millele on võimalik juurde teha kolm lisaülesannet

Antud juhul on tegu programmiga, mis töötab kuniks kasutaja soovib sellest väljuda. Seetõttu peame me ka vajadusel jälgima mis seisundis meie maatriks parasjagu on.

Maatriksi maksimaalne suurus mälus on fikseeritud makrotega LIMIT_ROWS ja LIMIT_COLS , mis määravad vastavalt maksimaalse ridade ja veergude arvu. Neid pead eraldi kasutama!

Programmis võib vastavalt kasutaja soovile olla kasutusel parasjagu väiksem osa maatriksist – sellisel juhul jääb lihtsalt otsa maatriksist kasutamata. Seetõttu on funktsioonide prototüüpides igal pool 2 muutujat int rows  ja int cols , mis sisaldavad hetkel kasutusel oleva maatriksi piire.

Lae alla aluskood: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/10_switch_basecode.c

Üldised nõuded

Need nõuded kehtivad olenemata millise osaga programmi lahendamisest tegeled.

  • Sinu lahendus peab võimalikult täpselt matkima etteantud näidisprogrammi.
  • Töö peab olema ehitatud etteantud aluskoodile.
    • Aluskoodi tohid mõistlikes piirides modifitseerida. Näiteks võib kasu olla tegevuste järjekorra muutmisest main() funktsioonis või funktsioonile GetIntInRange() täiendava parameetri lisamisest. Muudel juhtudel mõtle hoolikalt läbi kas muudatus on ikka mõistlik!
    • Aluskoodis on sinu jaoks juba valmis tehtud 2 funktsiooni, kasuta neid vastavalt vajadusele.
    • Aluskoodis on ette antud kahe esimese funktsiooni prototüübid millest peaksid lahendamist alustama tehes tunnitöö esimest osa.
  • Maatriksis olevad arvud on kõik vahemikus 0 – 99.
  • Kõik toimingud peavad olema korratavad ilma programmist väljumata.
  • Kõigi menüü valikute töötlev pool peab olema lahendatud eraldi funktsioonides.
    • switch()-i sees võid julgelt printida välja abiteksti, salvestada funktsioonidest tagastatavaid väärtusi jne. Äärmisel vajadusel võid ka mõne if lause sinna panna.
    • Täiendavaid tsükleid kindlasti main() funktsiooni kirjutada ei tohi!
  • Programm peab olema terviklik ja arusaadav ning töötama kuniks kasutaja soovib sellest ise väljuda.

Tunnitöö osa 1

Esimeses osas loome maatriksi kuvamise ja genereerimise.

Nõuded

  • Kasutaja saab genereerida n * m maatriksi
    • Maatriksi liikmeteks on juhuarvud vahemikus 0 – 99
    • n ja m on kasutaja poolt sisestatavad väärtused. Vajadusel loo piirangud kasutaja sisestusele
    • Genereerimise funktsioonis  GenerateMatrix()  tohid kasutada vaid do while()  tüüpi tsükleid.
    • Meeldetuletus: C funktsioonid on lihtsad ja teevad vaid ühte asja (ning teevad seda hästi)! Funktsioon GenerateMatrix() ei tohi tegeleda kasutajalt sisendi küsimisega!
  • Kasutaja saab kuvada maatriksit
    • Kuvamise funktsioonis tohid kasutada vaid while()  tüüpi tsükleid
    • Maatriks peab olema viisakalt joondus.
  • Kasutaja saab väljuda programmist

Tunnitöö osa 2

Teises tunnitöö osas loome funktsioonid ridade ja veergude omavahel vahetamiseks.

  • Kasutaja peab saama vahetada kaks enda valitud rida omavahel ära
    • Vahetamise funktsioonis tohid kasutada vaid for()  tüüpi tsükleid.
  • Kasutaja peab saama vahetada kaks enda valitud veergu omavahel

Tüüpilised vead

  • Copy-paste ehk korduv kood. Enamasti on selleks sisestus (nt sisesta ridade arv, sisesta veergude arv jne).
  • Off by one ehk ühega mööda. Meeldetuletuseks esimene rida on indeksiga 0.
  • Maagilised numbrid
  • Maatriksi operatsioonide lubamine enne maatriksi genereerimist. Näiteks sa ei saa kuvada maatriksid, mida ei ole veel genereeritud!
  • Vale tsükli tüübi kasutamine (Osa 1 ja 2 puhul on fikseeritud milliseid tsükli tüüpe tohid kasutada)
  • Ridade ja veergude arvu sassi ajamine. Proovi näiteks
    • genereerida 3 x 5 maatriks, vaheta ära read 1 ja 3
    • genereerida 5 x 3 maatriks, vaheta ära veerud 1 ja 3

Lisaülesanne 1: kustutamine

Lisame täiendava funktsionaalsuse olemasolevasse programmi

  • Kasutaja saab kustutada enda valitud rea.
  • Kasutaja saab kustutada enda valitud veeru.
  • Kustutatud rida või veerg eemaldatakse vahelt, mistõttu järgmised read või veerud tulevad varasemaks. Maatriksi suurus väheneb.
  • Lisa vajalik funktsionaalsus menüüsse.

Lisaülesanne 2: lisamine

Lisame täiendava funktsionaalsuse olemasolevasse programmi

  • Kasutaja saab soovitud asukohta lisada täiendava rea
  • Kasutaja saab soovitud asukohta lisada täiendava veeru
  • Kõik elemendid lisatavasse ritta või veergu genereeritakse juhuarvudega
  • Kõik read / veerud, mis paiknevad soovitud asukoha järel nihkuvad ühe võrra kaugemale. Maatriksi suurus suureneb.
  • Lisa vajalik funktsionaalsus menüüsse.

Lisaülesanne 3: transponeerimine

Lisame täiendava funktsionaalsuse olemasolevasse programmi

  • Kasutaja saab maatriksit transponeerida
  • Lisa vajalik funktsionaalsus menüüsse.

Pärast seda tundi peaksid

  • Oskama luua lõputult kestvaid menüü-programme
  • Teadma täiendavaid käske teksti väljastamiseks

Täiendav materjal

Kodutöö: vanuselise jaotuse looja

Ülesandeks on luua programm, mis suudab analüüsida ürituse külastajate vanuselist kuuluvust. Sisendiks tuleb teadmata arv külaliste vanuseid, kuniks programmi kasutaja sisestab nulli. Sellega katkestatakse lugemine ja väljastatakse statistika.

Grupeerimise nõuded:

  • Kõik alla 18 aastased grupeeritakse kui noored
  • Üle 18 aastaste kohta luuakse järjest 9 vanusegruppi, sammuga 5 eluaastat (nt 18 – 22, 23 – 27 jne)
  • Kõik, kelle vanus on suurem kui varasematesse gruppidesse mahtus, lahterda vanurite alla.

Andmestruktuur

Loendurid paiknevad massiivina, mille pikkus on määratud makroga GROUPS . Iga pesa massiivis on eraldi loendur vastavale vanusegrupile.

  • Indeksiga GROUPS - 1  hoitakse eakate loendurit
  • Indeksitega GROUPS - 2  hoitakse noorte loendurit
  • Indeksid 0  … GROUPS - 3  on jaotatud ühtlaselt vanusegruppidele. Näiteks indeks 0 on vanusevahemik 18 – 22; indeks 1 on vahemik 23 – 27 jne.

Programmi nõuded:

  • Grupeerimise väärtused peavad olema kergesti seadistatavad makrote abil
    • Gruppide arv
    • Grupi samm
    • Noorimate grupi ülemine piir
  • Ülejäänud programm peab olema võimeline vaid makrote  väärtuste muutmise peale kohanduma uute vahemikega.

Nõutud funktsioonid

Selle ülesande lahenduse raames peaksid looma kolm funktsiooni

  • Kasutaja sisendi valideerimiseks – kas see oli lubatud vahemikus
  • Isiku vanusegrupi indeksi leidmiseks. Grupi indeks tuleb tagastada funktsiooni poolt ja salvestada  idx  muutujasse.
  • Tulemuste väljastamiseks.

Võid luua ka neljanda funktsiooni, et programm struktuuri veelgi paremaks muutuja. Selleks sobiks algkoodis main funktsioonis oleva lõpmatu tsükli viimine eraldi funktsiooni.

Programmi struktuur

Oleme andnud sulle ette programmi üldise struktuuri koos vajalike makrotega. Peaksid neid kasutama, et programm

Algoritm

Oleme ka kirjeldanud ära suurema osa algoritmist, mis sul realiseerida tuleb. Mõned arvutused oleme sulle ka siiski jätnud välja mõelda – näiteks kuidas leida vanusevahemike otspunktid väljundis ning  ka veidi massiivi indekseerimist.

Näidis

Siin on näha programmi üldine käitumine. Näha on ka silumise jaoks tehtud lisaväljatrükk mis algab DEBUG  trükkimisega – see on kasulik enesekontrolliks mis massiivi indeks lõpuks välja arvutati – st mis loendurit lõpuks ikkagi suurendati.  Valmisprogrammis seda olema ei pea, kuid arenduse juures tasub kindlasti välja trükkida erinevaid väärtusi enesekontrolliks!

NB! Kui testid oma rakendust, proovi muuta makrosid GROUPS  ja GROUP_STEP  ning veendu, et kogu programm kohandub muudatustele!