Labori materjal
- Slaidid: Dünaamiline mälu 1
Laboriülesanded
Sellel nädalal on üks ülesanne, mida laiendab kaks edasijõudnute ülesannet.
Ülesanne: Juhuandmete generaator
Selle nädala ülesandeks on koostada juhuandmetega andmefaili generaator. Selliseid generaatoreid kasutatakse sageli rakenduste testimiseks enne kui on ligipääs reaalsetele andmetele.
Lae alla aluskood: https://blue.pri.ee/ttu/files/iax0584/aluskoodid/7_generator_starter.zip
Nõuded
- Ehita oma rakendus ette antud aluskoodi põhjale
- Küsi kasutajalt mitu kirjet ta soovib genereerida. Piirangut olla ei tohi!
- Kõik kirjed salvestatakse genereerimise käigus struktuurimassiivi, mis luuakse kasutades dünaamilist mälu.
- Vali juhuslikult etteantud valimitest välja eesnimi, perenimi ja õppekava kood.
- Genereeri juhuslikult sisseastumispunktid.
- Punktid on vahemikus 10 – 30 punkti. Otspunktid on kaasatud. Täpsus on 0,1 punkti (nt 24.7)
- Sorteeri genereeritud andmed perenime järgi. Kui perenimed ühtivad, sorteeri eesnime järgi.
- Väljund kirjuta faili järgnevas vormingus:
<indeks> <perenimi> <eesnimi> <õppekava kood> <sisseastumispunktid>- Indeks on unikaalne täisarv. Esimesel kirjel on indeksis 0, igal järgneval suureneb see 1 võrra.
- Veendu, et kogu mälu on programmi lõppedes vabastatud kasutades valgrind’i.
Qsordi võrdlusfunktsioon
Pakun välja kaks erinevat võrdlusfunktsiooni võimalust. Esimesel puhul tehakse tüübiteindused jooksvalt, likvideerides lisamuutujate loomise vajaduse.
1 2 3 4 5 6 7 8 9 10 11 12 |
int ComparCandidate(const void *a, const void *b) { // Get comparison for last names int ret = strcmp(((candidate *)a)->lName, ((candidate *)b)->lName); // When last names match, return difference by first name if (ret == 0) return strcmp(((candidate *)a)->fName, ((candidate *)b)->fName); // return difference by last name return ret; } |
Teisel juhul loome lisaviidad, mis võtavad täiendavalt mälu, kuid lihtsustavad koodi loetavust.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int ComparCandidate(const void *a, const void *b) { // Temporary cast pointers for readability candidate *pA = (candidate *)a; candidate *pB = (candidate *)b; // Get comparison for last names int ret = strcmp(a->lName, b->lName); // When last names match, return difference by first name if (ret == 0) return strcmp(a->fName, b->fName); // return difference by last name return ret; } |
Töövoog
- Loo vajalik struktuuri kirjeldus
- Küsi kasutajalt palju kirjeid vaja
- Küsi mälu vajalike kirjete hoidmiseks, kontrolli!
- Genereeri vajalikud kirjed
- Iga isiku jaoks pead genereerima kõik väljad juhuslikult.
- Iga struktuuri liikme valimiseks eesnimede, perenimede ja õppekava koodide valimist pead genereerima juhusliku numbri.
Vihje: Sa võid nime kas kopeerida enda struktuuri või hoiustada vaid viita nimele - Lisaks genereeri ja salvesta ka punktid.
Vihje: Mõtle matemaatiliselt – nt mis vahe on 30 ja 300!?! rand() funktsioon väljastab sulle täisarvu olenemata mida sa teha üritad sellega.
- Sorteeri struktuurid
- Kirjuta andmed väljundfaili
- Vabasta mälu
Kontrolli oma rakendust kasutades valgrindi! Seda mitte ainult lõpus, vaid ka siis kui rakendus käitub imelikult või jookseb kokku!
Testimine
Rakenduse väljund on võrdlemisi lihtne ja lühike
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
risto@risto-lt3-tux:~/Nextcloud/work/ttu/teaching/_generic/prog2/lab/wk7_generator/generator_solution$ valgrind ./generator ==12389== Memcheck, a memory error detector ==12389== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==12389== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==12389== Command: ./generator ==12389== The database contains: 103 first names 105 last names 3 curriculum codes How many candidates to generate? > 500 Successfully generated 500 entries Successfully written 500 lines to generated_candidates.txt ==12389== ==12389== HEAP SUMMARY: ==12389== in use at exit: 0 bytes in 0 blocks ==12389== total heap usage: 6 allocs, 6 frees, 13,016 bytes allocated ==12389== ==12389== All heap blocks were freed -- no leaks are possible ==12389== ==12389== For lists of detected and suppressed errors, rerun with: -s ==12389== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) |
Vaadates väljundfaili näeme, et tulemused on kenasti sorteeritud (näites vaid esimesed 15 rida)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
0 Aas Heidy IACB 27.9 1 Aas Juhan IACB 29.6 2 Aas Reet IACB 18.2 3 Aasa Anne EARB 10.1 4 Aasa Julia MVEB 13.8 5 Aasa Sven EARB 14.5 6 Aasa Taavi MVEB 16.1 7 Aasa Urve EARB 29.4 8 Aasa Valdo IACB 21.2 9 Allik Ivari IACB 21.3 10 Allik Kerttu MVEB 29.8 11 Allik Kerttu MVEB 21.4 12 Allik Laivi MVEB 24.2 13 Allik Peeter IACB 22.3 14 Allik Rainer IACB 17.5 |
Edasijõudnute ülesanne 1: väljundfaili formaat
Selle ülesande käigus lisame oma lahendusele CSV formaadi toe väljundis ning lubame kasutajal valida sobivlikku väljundformaati.
Nõuded
- Lisa oma programmile võimekus genereerida andmeid CSV formaadis.
- Esimene rida CSV failis peab olema päis väljade nimetustega
- Sellele järgnevad genereeritud andmeread, komadega eraldatud. NB! CSV puhul koma järele tühik ei käi.
- Küsi kasutajalt kummas formaadis ta soovib faili genereerida (tühikutega eraldatud või CSV) ning genereeri sobilik väljundfail.
- Tühikutega eraldatud faili laiendiks peab olema .txt , komadega eraldatud faili laiendiks peab olema .csv .
- Veendu, et CSV fail on korrektselt genereeritud – proovi avada või importida seda kasutades Libreoffice Calc’i või Microsoft Office’it ja vaata kas nad tuvastavad väljad korrektselt.
Edasijõudnute ülesanne 2: seadistused
Selles lisaülesandes muudame oma generaatori paindlikumaks ja lisame seadistuste võimekuse.
Nõuded
- Kõik seadistused tuleb hoida struktuuris – loo eraldi struktuuri kirjeldus ja struktuur selleks.
- Kõigil seadistustel peavad olema vaikeväärtused
- Programm peab kasutama vaikeväärtusi kui kasutaja ei soovi seadeid muuta. Kuidas kasutaja muutmissoovist teada peab anda võid ise otsustada.
Näiteks võib programm seda esimese asjana käivitudes küsida või saab kasutaja käivitada programmi kindla käsureaargumendiga, mis seadistuse avab. - Kasutajal peab soovi korral olema võimalik järgnevaid seadistusi muuta programmis sees olles
- Millised andmeväljad genereeritakse (igaühte peab olema eraldi võimalik sisse-välja lülitada)
- Väljundfaili nimi (ainult nimeosa, laiend valitakse automaatselt lähtuvalt valitud väljundformaadist!)
- Väljundformaadi seadistus (edasijõudnute ülesande 1 osa, tõsta struktuuri sisse)
- Genereeritavate kirjete arv (baasülesande osa, tõsta struktuuri sisse)
- Alam- ja ülempiir sisseastumispunktidele
- NB! Genereeritavate kirjete arvu tuleb küsida hoolimata sellest kas kasutaja soovis seadeid muuta või mitte. Eesmärk on lihtsalt hoida seadistusi koos.
- Kasutajale tuleb kuvada genereerimisseaded olenemata sellest kas ta soovis neid muuta või mitte.
Märkus: Soovi korral võid seadistusi hoida eraldi failis, kuid see pole vajalik. Kasutaja tehtud muudatusi seadetesse ei ole vaja meeles pidada järgmisel programmi käivitamisel. Küll aga kui sa soovid seadefaili kasutada, siis veendu, et kasutaja saab seadistusi muuta läbi programmi (ilma, et ta peaks seadefaili käsitsi muutma).
Vihje: Siin saab kolmikoperaatorit hõlpsasti ära kasutada
printf("First name: %10s\n", settings.genFirstName ? "Yes": "No");
Pärast seda tundi peaksid
- Oskama kasutada dünaamilist mälu
- Oskama kontrollida kas programmis on mälulekkeid
- Teadma mis olukorras on dünaamilist mälu mõistlik kasutada ja millal mitte
- Teadma dünaamilise mälu võludest ja valudest
- Tegema vahet pinumälul ja kuhjal ning mis muutujad kuhu lähevad.