PR1ET10: 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, siis mõne omadusega teeme juba täna tutvust.

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"

Üksiku tähemärgi kirjutame ülakomade vahel. Sõne koosneb sellistest tähemärkidest. NB! Kaldkriipsuga hakkavad erisümbolid (escape sequence) ja neid loetakse samuti üheks tähemärgiks kuna neid kodeeritakse ühe tähemärgina (nt \n  on üks tähemärk arvuti mälus kuna võtab vaid ühe baidi).

Näited:

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

NB! Pane tähele, et "a"  ja 'a'  on erinevad. Üks on sõne, teine on tähemärk.

Funktsioonid, mida saame kasutada teksti väljastamiseks

  • printf()  ehk print formatted. Tegu on kõige keerukama funktsiooniga seniõpitutest, mille abil saame trükkida kujundatud teksti ja väljastada ka kõiksugu muutujate sisu. Reavahetus käib käsitsi!
    Näiteks: printf("Hello, %s!\n", name);
  • puts()  ehk put string. Tegu on lihtsa väljastusfunktsiooniga, mis on mõeldud ühe tekstilõigu kuvamiseks. See ei toeta keerukaid formaate ega muutujatest väärtuste väljastamist. Reavahetus lisatakse automaatselt.
    Näiteks: puts("Hello, user!");
  • putchar()  ehk put character. See on kõige algselisem funktsioon kolmest. 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 funktsioonidese 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 mõõtmete suurused. Pärast funktsiooni edastamist ei ole võimalik massiivi mõõtmeid arvutuslikult leida! Erandiks on sõned (string), millest räägime tulevikus.

Mõned eripärad edastamisel

  • Kui soovid edastada tervet massiivi, olenemata selle mõõtmete arvust, kirjutame väljakutsesse vaid  massiivi nime Func(numbers);
  • Kui soovid 1-mõõtmelist 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-mõõtmelisest massiivist ( int numbers[N][M];  edastada ühe rea (tehniliselt kirjeldatuna vastava rea alguse asukoha mälus), täpsustame selle indeksi ja pikkuse Func(numbers[2], M); . Funktsioonis käsitle seda kui 1-mõõtmelist massiivi  Func(int numbs[], int n);
  • Ühte veergu 2-mõõtmelisest massivist  funktsiooni edastada ei ole võimalik, vähemalt mitte lihtsasti.
  • Kui soovid 2-mõõtmelisest massiivist int numbers[N][M];  edastada vaid ühe väärtuse, täpsustame funktsiooni väljakutses mõlemad indeksid Func(numbers[2][1]);

Kahe arvu omavahel vahetamine massiivis

Vahetamaks kahte arvu sobib lahenduseks sorteerimise 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). See on kusjuures levinud lähenemine ka kõiksugustes tehisaru põhistes lahendustes, mis on suuresti lihtsalt maatriksarvutused, mille põhimõtteid lineaaralgebras.

Massiivide algväärtustamine nulliks

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

Kui tegu on 2-mõõtmelise massiiviga, kasutame kahte komplekti loogelisi sulge.

Esitamisele kuuluvad ülesanded

Selles tunnis loome menüüprogrammi, mis töötab senikaua, kuniks kasutaja soovib sellest väljuda. Programmi raames tegeleme maatriksi manipuleerimisega. Programmi keskmes on mitmed piirjuhtumid (näiteks mis saab siis, kui kasutaja soovib manipuleerida maatriksit, mida ei ole olemas).

Alusta näidisprogrammiga tutvumisest, misjärel saad edasi liikuda ja luua ise samalaadse rakenduse.

Tunnitöö näidisprogramm

Näidisprogramm on esitatud kompileeritud kujul, st sul on võimalik proovida esmalt kuidas lõpplahendus peaks töötama. Näidisrakendusi on kolm tükki, näitamaks milline näeb välja rakendus erinevates etappides. Proovi näidisrakendusi enne töö alustamist! Sinu loodav rakendus peab võimalikult lähedaselt matkima näidisrakenduse tööd.

Näidisprogrammid on kompileeritud x86-64 arhitektuurile ehk töötab kõigis kooliarvutites ning ka enamikes isiklikes arvutites: https://blue.pri.ee/ttu/files/iax0583/demoprogrammid/wk10_solution_binaries.zip

NB! Programmile tuleb anda käivitamisõigused (suvalist internetist leidud programmi ei tohi käivitada). Õiguste muutmine on ühekordne tegevus. Selleks käivita käsk:

See lisab (chmod – change mode) kasutajale (u – user) õigused programmi käivitada (x – execute).

Pärast seda saad programmi käivitada tavapäraselt, st ./program_name

Kirjeldus

Tänane tunnitöö on jaotatud kaheks baasosaks ning lisaülesanneteks. Mõlemad baasosad on eraldi kaitstavad.

Tegu on lõpmatult käiva menüü-programmiga, millel on eraldi valik väljumiseks. Seetõttu on oluline jälgida rakenduse olekut – meie mõistes mis seisundis parasjagu maatriks on. Näiteks kui maatriksil on 0 rida, siis ridu (ega ka veerge) pole võimalik vahetada.

Programmi mälus on maatriks deklareeritud fikseeritud maksimaalse suurusega, milleks kasutatakse makrosid  LIMIT_ROWS ja LIMIT_COLS .  Rakenduse töö ajal võidakse kasutada maatriksist vaid osalist suurust – nt kui maksimum ridade arv on 10, kuid kasutaja loob 5-realise maatriksi. Sellisel juhul hoiame ikkagi mälus kümme rida, kuid genereerime ja kuvame kasutajale neist vaid esimesed 5. Seetõttu on mitmetes funktsiooni prototüüpides kasutusel 2 muutujat – int rows  ja int cols , mis sisaldavad parasjagu aktiivset maatriksi suurust.

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 ja põhjendatud!
    • Aluskoodis on sinu jaoks juba valmis tehtud kaks funktsiooni, kasuta neid vastavalt vajadusele.
    • Aluskoodis on ette antud kahe esimese sinu poolt loodava funktsiooni prototüübid, millest peaksid oma lahenduse loomist alustama.
  • Rakendus peab töötama ka olukorras, kus ridade ja veergude arvud on erinevad, st tegu pole ruutmaatriksiga.
  • Kõik maatriksis olevad arvud on vahemikus 0 – 99.
  • Kõik toimingud peavad olema korratavad ilma programmist väljumata.
  • Kõigi menüü valikute töötlev kood peab olema lahendatud eraldi funktsioonides.
    • switch()  lause sees võid printida välja abitekstr, salvestada funktsioonidest tagastatavaid väärtusi, teostada omistuslauseid ja arvutustehteid. Vajadusel võid ka mõne if  lause lisada.
    • Ära deklareeri switch()  sees uusi muutujaid!
    • Uusi tsükleid main()  funktsiooni kirjutada ei tohi!
  • Programm peab olema terviklik ja arusaadav ning töötama, kuniks kasutaja soovib sellest ise väljuda.

Tunnitöö osa 1 [W10-1]: Maatriksi genereerimine ja kuvamine

Esimeses osas loome maatriksi kuvamise ja genereerimise. Ülesande raames harjutad ka kindlat tüüpi tsüklite kasutamist!

Nõuded

  • Kasutaja saab genereerida n * m maatriksi
    • Maatriksi elementide genereerimine toimub funktsioonis GenerateMatrix()
    • Maatriksi elementideks on juhuslikud täisarvud vahemikus 0 – 99
    • Ridade arv n ja veergude arv m on kasutaja poolt sisestatavad väärtused.
    • Maatriksi läbikäiguks genereerimise funktsioonis 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 aktiivse maatriksi
    • Maatriksi kuvamine toimub funktsioonis DisplayMatrix()
    • Kuvamise funktsioonis tohid kasutada vaid while()  tüüpi tsükleid
    • Maatriks peab olema joondatud
  • Kasutaja saab lisada maatriksi lõppu uue rea
    • Rea lisamine toimub funktsioonis AddRow()
    • Rea lisamine toimub kasutades for()  tüüpi tsüklit
  • Kasutaja saab programmist väljuda

Tunnitöö osa 2 [W10-2]: Ridade ja veergude vahetamine

Tunnitöö teine pool lisab rakendusse ridade ja veergude vahetamise ning mugavusfunktsiooni automaatseks maatriksi väljastuseks ning selle juhtimiseks.

  • Kasutaja peab saama vahetada kahes enda poolt valitud reas paiknevad väärtused
  • Kasutaja peab saama vahetada kahes enda poolt valitud veerus paiknevad väärtused
  • Kasutaja peab saama juhtida maatriksi automaatset väljastuse kuvamist (sees / väljas)
  • Juhul kui maatriksi automaatne väljastus on sees, kuvatakse maatriks ainult selliste tegevuste järel, mis modifitseerivad maatriksit või selle elemente

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 arvud
  • Tegevuste lubamine enne maatriksi genereerimist. Näiteks sa ei saa kuvada maatriksit, mida ei ole veel genereeritud või millest on kõik read ära kustutatud.
  • Vale tsükli tüübi kasutamine (esimeses osas on tsükli tüübid ette määratud)
  • 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
  • Konstantide vale kasutamine – muuda maksimaalne ridade või veergude arvu määrav makro ära ja testi oma rakendust

Lisaülesanne 1 [W10-3]: Lisamine ja kustutamine

Täiustame olemasoleva maatriksi suuruse modifitseerimist järgneva funktsionaalsusega

  • Kasutaja saab lisada uue veeru kõige lõppu
  • 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 tuuakse varasemaks. Maatriksi suurus väheneb.
  • Lisa vajalik funktsionaalsus menüüsse

Lisaülesanne 3 [W10-4]: Peegeldamine

Lisame täiendava funktsionaalsuse olemasolevasse programmi

  • Kasutaja saab maatriksit transponeerida
  • Kasutaja saab peegeldada maatriksit ümber oma horisontaaltelje
  • Kasutaja saab peegeldada maatriksit ümber oma vertikaaltelje
  • 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
  • Eristama tähemärki ja sõnet
  • Oskama edastada ja funktsioonis vastu võtta
    • tervet maatriksit
    • maatriksi ühte rida
    • maatriksi ühte elementi

Täiendav materjal