Praktikumi materjal
- Slaidid: Dünaamiline mälu 1
Praktikumi ülesanded
Selle praktikumi ülesandeks on luua juhuandmete generaator. Ülesannet laiendab kaks lisaülesannet.
Ülesanne [W07-1]: Juhuandmete generaator
Praktikumiülesandeks on koostada juhuandmetega andmefaili generaator. Selliseid generaatoreid kasutatakse sageli rakenduste testimiseks enne, kui saadakse ligipääs reaalsetele andmetele. Päris mitmetes selle kursuse praktikumiülesandes on testandmed genereeritud sarnasel viisil.
NB! Kuigi üks soovituslikest juhuandmete genereerimise viisidest on kasutada tehisaru, siis alati ei tööta see just kuigi hästi või osutub absurdselt kalliks – nt kui soovid genereerida miljoneid ridu keerukaid andmeid.
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. Ülempiiri luua 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 (nt 24,7)
- Punktid on vahemikus 10,0 – 30,0 punkti. Otspunktid on kaasatud.
- Täpsus on 0,1 punkti
- 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. Esimese kirje indeks on 0, igal järgneval suureneb see 1 võrra.
- Veendu, et kogu mälu on programmi lõppedes vabastatud kasutades Valgrind’i
Töövoog
- Loo vajalik struktuuri kirjeldus, salvesta see päisefaili
- Küsi kasutajalt mitu kirjet tuleks genereerida
- Küsi mälu vajalike kirjete hoidmiseks. Kontrolli, et mälu saadi!
- Genereeri vajalikud kirjed
- Iga isiku jaoks pead genereerima kõik väljad juhuslikult
- Eesnimi, perenimi ja õppekavakood tuleb juhuslikult valida olemasolevatest valimitest. Selleks pead genereerima täisarvu (nt mitmes eesnimi valimist)
Vihje: Sa võid nime kas kopeerida enda struktuuri või hoiustada vaid viita nimele - Genereeri vastuvõtupunktid (10,0 <= punktid <= 30,0 täpsusega 0,1)
Vihje: Mõtle matemaatilistele omadustele – nt mis vahe on 30 ja 300!? rand() funktsioon tagastab alati täisarvu ning seda muuta ei saa.
- Sorteeri massiiv
- Mõtle ka miks on siin halb idee kasutada eksponentsiaalse keerukuse kasvuga meetodeid (bubble/insertion/selection)
- 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!
Qsordi võrdlusfunktsioon
Pakun välja kaks erinevat võrdlusfunktsiooni võimalust. Vali see millest saad paremini aru, või kirjuta enda lahendus.
Esimene näide kasutab tüübiteisendusi jooksvalt, vältides lisamuutujate loomise vajadust.
|
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; } |
Teine näide sisaldab lisaviitasid, 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(pA->lName, pB->lName); // When last names match, return difference by first name if (ret == 0) return strcmp(pA->fName, pB->fName); // return difference by last name return ret; } |
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) |
Kontrolli oma väljundfaili ning veendu tulemuste korrektsuses. Sinu väljundfail saab olema erinev, andmed on juhuslikult genereeritud.
|
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 |
Lisaülesanne 1 [W07-2]: Väljundfaili formaat
Esimese lisaülesande käigus lisad oma lahendusele CSV formaadi toe. Kasutaja saab valida sobiva väljundformaadi – kas tühikutega või komadega eraldatud väljundfail.
Nõuded
- Lisa oma programmile võimekus genereerida andmeid CSV formaadis
- Esimene rida CSV failis peab olema päis, mis sisaldab genereeritud andmeväljade nimetusi
- Sellele järgnevad genereeritud andmeread. Iga andmeväli peab olema eraldatud komaga. NB! CSV failis 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 genereeritud faili kasutades Libreoffice Calc’i või Microsoft Office’it ja kontrolli kas väljad tuvastati korrektselt.
Lisaülesanne 2 [W07-3]: Seadistused
Selles lisaülesandes muudame oma generaatori paindlikumaks ja lisame seadistuste võimekuse.
Nõuded
- Kõik seaded tuleb hoida struktuuri liikmetena – loo uus struktuuri kirjeldus seadistuste hoidmiseks
- Kõigil seadistustel peavad olema vaikeväärtused
- Kui kasutaja ei soovi seadistusi muuta, peab programm kasutama vaikeväärtusi. Kuidas kasutaja muutmissoovist teada peab andma, 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 muuta järgnevaid seadistusi
- Millised andmeväljad genereeritakse (iga andmevälja peab olema võimalik sisse-välja lülitada)
- Väljundfaili nimi (ainult nimeosa, faililaiend valitakse automaatselt lähtuvalt valitud väljundformaadist!)
- Väljundformaadi valik (lisaülesande 1 osa, tõsta struktuuri sisse)
- Genereeritavate kirjete arv (baasülesande osa, tõsta struktuuri sisse)
- Sisseastumispunktide vahemik (alam- ja ülempiir)
- NB! Genereeritavate kirjete arvu tuleb küsida olenemata sellest, kas kasutaja soovis seadeid muuta või mitte. Eesmärk on hoida kõik seadistused vastavas struktuuris koos.
- Kasutajale tuleb kuvada ülevaade genereerimisel kasutavatest seadetest. Seda olenemata kas ta soovis neid muuta või mitte.
Märkus: Soovi korral võid seadistuste väärtusi 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.
Täiendav materjal
- Käsitsi mälu haldamine
https://beej.us/guide/bgc/html/split/manual-memory-allocation.html#manual-memory-allocation - Mälulekked
https://www.geeksforgeeks.org/what-is-memory-leak-how-can-we-avoid/ - Mälulekete kontroll Valgrindiga
https://valgrind.org/docs/manual/quick-start.html