Differences between revisions 29 and 281 (spanning 252 versions)
Revision 29 as of 2010-03-23 14:17:34
Size: 8582
Editor: sarkoci
Comment:
Revision 281 as of 2015-02-17 14:53:06
Size: 22294
Editor: sarkoci
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Zadania =

Všeobecné zásady:

 * Vypracované zadania zasielajte na sarkoci@math.sk, prikladajte ich k e-mailu skomprimované ako prílohu a subject nastavte na "seminar z programovania".
 * Pred odovzdaním riešenia skontrolujte, či sa nedopúšťate niektorej spomedzi [[#chyby|často sa vyskytujúcich chýb]].
 * Zdrojový kód odsádzajte.
 * Program rozbíjajte na zmysluplné funkčné bloky ktoré sú realizované funkciami - čím viac, tým lepšie.
 * Ošetrujte chybové stavy.
 * Programujte tak, aby kompilátor nevyhlasoval ani jedno varovanie pri pedantnom móde kompilácie.

=== 1 ===

Naprogramujte funkciu ktorá zadané dynamicky allokované <<latex($n$)>>-prvkové pole premenných typu `int`:
 * Inicializuje na hodnotu 0.
 * Inicializuje na aritmetickú postupnosť <<latex($\{a+i.b\}_{i\in \mathbf{Z}_{n}}$)>> so zadanými parametrami <<latex($a,b\in\mathbf{Z}$)>>.
 * Inicializuje na postupnosť náhodne generovaných celých čísel.
 * Analyzuje a zisťuje pozíciu a dĺžku najdlhšej klesajúcej podpostupnosti bezprostredne po sebe nasledujúcich prvkov.
 * Sčituje a vracia hodnotu súčtu všetkých prvkov v poli.
 * Analyzuje a vracia aritmetický priemer prvkov v poli.
 * Analyzuje a vracia rozptyl prvkov v poli.

Design funkcií (čiže voľba návratových typov a argumentov) je na vás. Urobte to ale tak, aby funkcie referovali všetky možné chybové stavy aké pri ich vykonávaní môžu nastať.

=== 2 ===

Napíšte program ktorý od uživateľa z klávesnice načíta prirodzené číslo <<latex($n$)>> a následne, metódou Erastotenovho sita, zistí všetky prvočísla nie väčšie než <<latex($n$)>>. Pamäť v ktorej Erastotenov algoritmus vykonáva Erastotenovské značkovanie allokujte dynamicky.

=== 3 ===

Budeme pracovať s racionálnymi číslami reprezentovanými v tvare zlomku. Za účelom reprezentácie takéhoto zlomku si zavedieme zavedieme datový typ `zlomok` a to bude štruktúra o dvoch členských premenných: čitateľ bude reprezentovať premenná typu `int`, menovateľ bude reprezentovať premenná typu `unsigned int`. Implementujte nasledujúce funkcie:
 * funkciu ktorá porovná dva takto reprezentované zlomky a cez návratový typ referuje, ktorý z nich je väčší.
 * funkciu ktorá vypočíta súčet dvoch zlomkov
 * funkciu ktorá vypočíta rozdiel dvoch zlomkov
 * funkciu ktorá vypočíta súčin dvoch zlomkov
 * funkciu ktorá vypočíta podiel dvoch zlomkov
Funkcie implementujte tak, aby výsledok výpočtu reprezentovali a odovzdali opäť ako zlomok.

=== 4 ===

K riešeniu úlohy 1. doprogramujte funkciu ktorá zadané pole premenných typu int preusporiada vzostupne. To znamená, že výsledné pole obsahuje presne tie isté prvky ako zadané pole, ale hodnoty v ňom uložené su neklesajúcou funkciou indexu. <!> Aspoň približné riešenie zaslať do 21.Marca a to aj v prípade, že ste ešte úspešne neodovzdali zadanie 1.

=== Priebežný stav ===

|| ID || 1 || 2 || 3 || 4 ||
|| 41458 || || || || ||
|| 67640 || || || || ||
|| 67644 || || || || ||
|| 67654 || <!> || <!> || || ||
|| 67660 || || || || ||
|| 67667 || || || || ||
|| 67674 || <!> || (./) || (./) || ||
|| 67678 || || || || ||
|| 67682 || || || || ||
|| 67687 || || || || ||
|| 67692 || || || || ||
|| 67698 || <!> || (./) || || ||
|| 67705 || || || || ||
|| 67708 || || || || ||
|| 67718 || || || || ||
|| 67720 || || || || ||
|| 67725 || || || || ||
|| 67728 || || || || ||
|| 67733 || || || || ||
|| 67737 || <!> || || || ||
|| 67743 || <!> || <!> || || ||
|| 67746 || || || || ||
|| 69782 || || || || ||
 
##= Všeobecné =
##
##[[http://en.wikipedia.org/wiki/Necessary_and_sufficient_condition|Nutnou podmienkou]] k absolvovaniu skúšky je získanie zápočtu. Získanie zápočtu je podmienené úspešným #odovzdaním 4 spomedzi 8 zadaní. Päťnásobok úspešne odovzdaných zadaní sa v podobe bodov prenáša ku skúške. Samotná skúška pozostáva z písomnej a ústnej časti, obe sú po #30 bodov. Ako pomôcku si na skúšku možno priniesť akúkoľvek písomnosť, elektronické pomôcky sú zakázané.

= Organizačné informácie =

Pre ich citlivú povahu budem uvádzať v systéme anjadu.

= Štúdijné materiály =

|| Slajdy k prednáškam || Iné zdroje ||
|| || [[MercurialReceptar|Mercurial: Varíme z ortuti - zdravo, rýchlo, lacno]] ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/01_seminar_z_programovania.pdf|Pamať, jej adresovanie a smerníky]] || [[MercurialReceptar|Mercurial: Varíme z ortuti - zdravo, rýchlo, lacno]] ||
|| || [[http://mercurial.selenic.com/quickstart/|Mercurial: Quick Start]] ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/02_seminar_z_programovania.pdf|Dynamická allokácia pamäti]] || [[http://mercurial.selenic.com/quickstart/|Mercurial: Quick Start]] ||
|| || [[http://hgbook.red-bean.com/read/|Mercurial: The Definitive Guide]] ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/03_seminar_z_programovania.pdf|Reprezentácia matíc]] || [[http://hgbook.red-bean.com/read/|Mercurial: The Definitive Guide]] ||
|| || [[http://mercurial.selenic.com/wiki/CzechMercurial|Mercurial: Návod v českom jazyku]] ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/06_seminar_z_programovania.pdf|Nizkoúrovňové I/O]] || [[http://mercurial.selenic.com/wiki/CzechMercurial|Mercurial: Návod v českom jazyku]] ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/05_seminar_z_programovania.pdf|Quicksort]] || ||
##|| [[http://www.math.sk/sarkoci/MPM1SZP/04_seminar_z_programovania.pdf|Výpočtová zložitosť I., Rekurzia]] || ||

##= Zadania =
##
##Akceptujem len také vypracovania zadaní, ktoré v plnej miere vyhovujú zneniu zadania a v ktorých sa nevyskytuje ani jedna chyba zo zoznamu [[#chyby|častých chýb]]. Pri každom zadaní je uvedený termín do kedy je možné jeho vypracovanie úspešne odovzdať. Po tomto termíne vypracovania neakceptujem. Neodovzdávajte vypracovania okopírované #od svojich kolegov. Zvyčajne na to veľmi ľahko prídem. Za <<latex($n$)>>-tý pokus o odovzdanie práce druhej osoby získate formálne <<latex($-n$)>> odovzdaných zadaní. Pretože nie je v mojich silách robiť detektíva a zisťovať kto čo od koho odpísal, záporné body získajú všetky strany plagiátorského kontraktu.
##
##=== Termíny pre odovzdanie zadaní ===
##
## * Prvé zadanie - 18. Apríl, 2011
## * Druhé zadanie - 18. Apríl, 2011
##
##=== Hinty ===
##
## * Zadanie '''1'''. Úloha naprogramovať funkciu ktorá generuje náhodnú permutáciu predpísaného cyklického typu má, okrem mnohých komplikovaných, aj jedno naozaj elegantné riešenie. Ako návod na jeho nájdenie si sami pre seba zodpovedzte nasledujúcu otázku: ak sú <<latex($f$)>> a <<latex($g$)>> permutácie množiny <<latex($X$)>>, #v akom vzťahu je cyklický typ permutácie <<latex($g\circ f\circ g^{-1}$)>> k cyklickému typu permutácie <<latex($f$)>>?
##
##=== Priebežný stav ===
##
##|| ID || 1 || 3 || 4 || 5 || 6 || protokol k zadaniu 3 || ine bonusy || <<latex($\sum$)>> ||
## Barborikova Lucia:
##|| 67682 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Cifra Stefan:
##|| 41458 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Daniel Patrik:
##||<#FFFFAA> 7430 || {*} || {*} || {*} || {*} || {o} || || 3 || 35 ||
## Dobňak Peter:
##||<#FFFFAA> 7439 || {o} || {*} || {*} || {*} || {*} || || 3 || 35 ||
## Jasa~n Peter:
##|| 7449 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Juhásová Ľubica:
##|| 7425 || {o} || {o} || {o} || {*} || {o} || || || 8 ||
## Kósa Balázs:
##||<#FFFFAA> 7433 || {*} || {*} || {*} || {*} || {*} || 4 || 3 || 47 ||
## Krull Samuel
##|| 7503 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Lukáč Matej
##||<#FFFFAA> 7455 || {o} || {*} || {*} || {*} || {*} || 4 || 3 || 39 ||
## Mesiar Martin
##|| 7446 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Meszáros Michal
##||<#FFFFAA>7465 || {o} || {*} || {*} || {*} || {*} || || 2 || 34 ||
## Očenáš Martin
##|| 64702 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Petrovič Pavol
##||<#FFFFAA> 64426 || {o} || {*} || {*} || {*} || {*} || || 1 || 25 ||
## Škabla Peter
##||<#FFFFAA> 7408 || {*} || {o} || {*} || {*} || {*} || || 2 || 34 ||
## Šťastná Hilda
##|| 40071 || {*} || {*} || {o} || {o} || {*} || || 3 || 27 ||
## Tucsok Nikolett:
##|| 67733 || {*} || {o} || {o} || {o} || {o} || || || 8 ||
## Vranková Andrea:
##|| 7431 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Zubaj Lukáš
##|| 7415 || {o} || {o} || {o} || {o} || {o} || || || 0 ||
## Priklad
##|| || || || || || || || || ||
##|| napr. || {*} || {X} || {o} || {*} || {*} || {X} || 3 || +3 ||
##|| vysv. || +8 || -8 || +0 || +8 || +8 || -16 || +3 || = ||

##=== Zadanie 1 ===
##
##Naprogramujte funkciu ktorá zadané dynamicky allokované <<latex($n$)>>-prvkové pole premenných typu `int`:
## * Inicializuje na hodnotu 0.
## * Inicializuje na aritmetickú postupnosť <<latex($\{a+i.b\}_{i\in \mathbf{Z}_{n}}$)>> so zadanými parametrami <<latex($a,b\in\mathbf{Z}$)>>.
## * Inicializuje na postupnosť náhodne generovaných celých čísel.
## * Analyzuje a zisťuje pozíciu a dĺžku najdlhšej klesajúcej podpostupnosti bezprostredne po sebe nasledujúcich prvkov.
## * Sčituje a vracia hodnotu súčtu všetkých prvkov v poli.
## * Analyzuje a vracia aritmetický priemer prvkov v poli.
## * Analyzuje a vracia rozptyl prvkov v poli.
##
##Design funkcií (čiže voľba návratových typov a argumentov) je na vás.
##
##=== 2 ===
##
##Napíšte program ktorý od uživateľa z klávesnice načíta prirodzené číslo <<latex($n$)>> a následne, metódou Erastotenovho sita, ##zistí všetky prvočísla nie väčšie než <<latex($n$)>>. Pamäť v ktorej Erastotenov algoritmus vykonáva Erastotenovské značkovanie ##allokujte dynamicky.
##
##=== 3 ===
##
##Budeme pracovať s racionálnymi číslami reprezentovanými v tvare zlomku. Za účelom reprezentácie takéhoto zlomku si zavedieme ##zavedieme datový typ `zlomok` a to bude štruktúra o dvoch členských premenných: čitateľ bude reprezentovať premenná typu `int`, ##menovateľ bude reprezentovať premenná typu `unsigned int`. Implementujte nasledujúce funkcie:
## * funkciu ktorá porovná dva takto reprezentované zlomky a cez návratový typ referuje, ktorý z nich je väčší.
## * funkciu ktorá vypočíta súčet dvoch zlomkov
## * funkciu ktorá vypočíta rozdiel dvoch zlomkov
## * funkciu ktorá vypočíta súčin dvoch zlomkov
## * funkciu ktorá vypočíta podiel dvoch zlomkov
##Funkcie implementujte tak, aby výsledok výpočtu reprezentovali a odovzdali opäť ako zlomok.
##
##=== 4 ===
##
##K riešeniu úlohy 1. doprogramujte funkciu ktorá zadané pole premenných typu int preusporiada vzostupne. To znamená, že výsledné ##pole obsahuje presne tie isté prvky ako zadané pole, ale hodnoty v ňom uložené su neklesajúcou funkciou indexu. <!> Aspoň ##približné riešenie zaslať do 21.Marca a to aj v prípade, že ste ešte úspešne neodovzdali zadanie 1.
##
##=== 5 ===
##
##Navrhnite datový typ reprezentujúci maticu (v matematickom zmysle slova) čísel typu double. Taký datový typ by mal niesť ##informáciu o počte riadkov, počte stĺpcov a, samozrejme, o hodnotách jednotlivých prvkov matice. Je jasné, že tu hovoríme o ##nejakej štruktúre. Okrem týchto vecí môže taký datový typ zastrešovať aj rôzne servisné a obslužné informácie - to už závisí od ##vašeho programátorského vkusu a rôznych implementačných nutností na ktoré cestou narazíte.
##
##Pre tento datový typ potom naprogramujte funkciu ktorá:
## * vytvorí a pripraví všetky potrebné štruktúry pre neinicializovanú maticu typu <<latex($m\times n$)>>
## * uvolní pamäť po štruktúrach reprezentujúcich zadanú maticu
## * zadanú maticu skopíruje do inej, tiež zadanej matice
## * zadanú maticu inicializuje na nulovú maticu
## * zadanú maticu inicializuje na jednotkovú maticu
## * zadanú maticu inicializuje na maticu náhodných hodnôt
## * vypočíta euklidovskú normu zadanej matice
## * maticu transponuje
## * vypočíta súčin dvoch zadaných matíc a uloží ho do tretej zadanej matice
## * Na zadanú maticu aplikuje také elementárne riadkové operácie ktoré ju prevedú na dolnú trojuholníkovú maticu a súbežne ich ##aplikuje na inú, tiež zadanú maticu
## * nad zadanou maticou vykoná Gramm-Schmidtovu ortogonalizáciu
##
##=== 6 ===
##
##Čo je to šedotónový obrázok formátu PGM typu P5 sa dozviete na internete - napríklad tu [[http://morse.cs.byu.edu/450/resources/pnm.html|tu]] alebo aj [[http://codeding.com/?article=3|tu]] ale nie len. Ako konkrétne príklady obrázkov v tomto formáte sú vám k ##dispozícii [[attachment:baboon.pgm|baboon]], [[attachment:barbara.pgm|barbara]] a [[attachment:lena.pgm|lena]]. Vašou úlohou je ##navrhnúť jednoduchý datový typ na reprezentáciu šedotónového obrázku o 256 úrovniach šedi (čiže presne toho, čo reprezentuje ##formát PGM). Ďalej, pre tento datový typ naprogramujte funkciu ktorá:
## * vytvorí a pripraví všetky potrebné štruktúry pre obrázok zadaných rozmerov a všetky stupne šedi nastaví na čiernu
## * vytvorí a pripraví všetky potrebné štruktúry pre obrázok reprezentovaný vo formáte PGM typu P5 v súbore zadaného mena a ##hodnoty šedi takto vytvoreného obrázku inicializuje hodnotami prečítanými zo súboru
## * zadanú obdĺžnikovitú časť jedného obrázku okopíruje na zadanú pozíciu v druhom obrázku
## * nad obrázkom vykoná primitívnu binarizáciu, čiže - čo je svetlejšie než polovičná šedá zostane úplne biele a čo je tvamvšie než polovičná šedá zostane úplne čierne
## * na obrázok aplikuje [[http://en.wikipedia.org/wiki/Sobel_operator|Sobelov hranový detektor]]
## * na obrázok aplikuje nejaký algoritmus [[http://homepages.inf.ed.ac.uk/rbf/HIPR2/adpthrsh.htm|lokálnej adaptívnej binarizácie]] - voľba konkrétneho algoritmu je otázkou vašeho vkusu
## * obrázok uloží na disk do súboru zadaného mena vo formáte PGM typu P5
##
##=== 7 ===
##
##Naprogramujte jednoduchú aplikáciu `obrazkovac` na spracovanie obrázkov vo formáte PGM typu P5. Aplikácii sa všetky pokyny pre jej činnosť budú odovzdávať ako parametre príkazového riadku. Aplikácia zo zadaného súboru (hovorme mu `vstupny_obrazok`, ale môže sa samozrejme volať aj inakšie) prečíta šedotónový obrázok a následne naň aplikuje rôzne algoritmy spracovania obrazu v takom poradí v akom sú uvedené v príkazovom riadku. Syntax príkazového riadku:
## `obrazkovac [parametre] vstupny_obrazok`
##počíta s nasledujúcimi parametrami:
## * `-b` aktuálny obrázok zbinarizuj primitívnou binarizačnou metódou,
## * `-lab` na aktuálny obrázok aplikuj algoritmus lokálnej adaptívnej binarizácie,
## * `-s` na aktuálny obrázok aplikuj Sobelov hranový dekektor,
## * `-o vystupny_obrazok` aktuálny obrázok uloží do súboru s menom `vystupny_obrazok` vo formáte PGM typu P5.
##Čiže napríklad
## `obrazkovac -s -s -o dvojhrany.pgm -lab -s -lab -o definitivne.pgm baboon.pgm`
##vezme obrázok opice, aplikuje naň Sobelov detektor a potom ešte raz Sobelov detektor, medzivýsledok uloží do súboru ##`dvojhrany.pgm`, ďalej na obraz aplikuje lokálnu adaptívnu binarizáciu, opäť Sobelov detektor a ešte raz lokálnu adaptívnu ##binarizáciu a aktuálny obraz uloží do `definitivne.pgm`.
##
##Všetky funkcie na prácu s reťazcami si naprogramujte sami, hlavičkový súbor `string.h` je pre toto zadanie tabu.
##
##=== 8 (*) ===
##
##K riešeniu úloh 1. a 4. doprogramujte merge-sort.
Line 71: Line 159:
=== Časté chyby === == Časté chyby ==

Každodenná programátorská skúsenosť aj vás naučí, že čitateľnosť a zrozumiteľnosť zdrojáku je nie len nutnou podmienkou jeho trvalej spravovateľnosti ale aj cestou k zachovaniu psychyckého zdravia - ako vašeho tak aj môjho. Na užitočnosť štábnej kultúry prišli už naši predkovia, ktorí stáli pri kolíske programovacích jazykov. Budeme sa toho držať aj my. Toto je zoznam pravidiel, ktorých splnenie bude nutnou podmienkou k tomu, aby som vaše zdrojáky vôbec študoval. Preto vám radím, aby ste sa ich snažili dodržiavať už od prvého zadania.
Line 74: Line 164:
   a. Funkcia alebo procedúra má vykonávať ''jednu'', čo možno ''najjednoduchšiu'' činnosť a túto činnosť má vykonávať dobre.    a. Každá jedna funkcia alebo procedúra má vykonávať ''jednu'', čo možno ''najjednoduchšiu'' činnosť a túto činnosť má vykonávať dobre. Áno, existujú výnimky z tohoto pravidla, ale na tomto seminári sa s nimi nestretneme.
Line 76: Line 166:
   a. Veľké datové typy a komplikované datové štruktúry sa funkciám ''nikdy'' neodovzdávajú ako argumenty. Namieto toho sa ako argumenty odovdávajú iba smerníky na ne. Prečo? Na prednáške sa dozviete, že každé odovzdanie argumentu funkcii pri jej volaní obnáša kopírovanie hodnôt argumentov. Jazyk C toto kopírovanie zakrýva ale to neznamená, že k nemu nedochádza. Ak sú argumentami funkcie nejaké veľké štruktúry, znamená to veľa kopírovania a to je neefektívne. Naproti tomu smerník je iba jedno relatívne malé číslo a to sa kopíruje ľahko.
   a. Funkcie vymýšlajte tak, aby referovali všetky možné typy chybových stavov ktoré pri ich vykonávaní môžu nastať. Príznaky týchto chybových stavov referujú primárne cez návratovú hodnotu a ak len ak sa to nedá nejak inak.
   a. Zásada o pred-objektovej disciplíne: Všetky "konštruktory" (čiže funkcie, ktoré sa starajú o allokáciu pamäte pre komplikované datové štruktúry) allokujú ''celé'' datové štruktúry a volajúcemu procesu cez navratovu hodnotu odovzdávajú iba ich adresy. Všetky "deštruktory" (čiže funkcie, ktoré sa starajú o uvoľnovanie pamäte po komplikovaných datových štruktúrach) uvoľňujú pamäť po ''celých'' datových štruktúrach a ako argument preberajú iba smerník na štruktúru ktorú treba zničiť.
   a. Všetky "konštruktory" (čiže funkcie, ktoré sa starajú o allokáciu pamäte pre komplikované datové štruktúry) treba implementovať tak, aby v prípade keď sa proces allokacie pamäte nepodarí z nejakého dôvodu úspešne zavŕšiť, uvolnili tie časti pamäte ktoré sa im ešte pred nastaním problému allokovať podarilo. Motivácia pre túto zásadu je úplne jasná: kedykoľvek proces allokácie niekde uviazne, treba volajúcemu procesu namiesto allokovanej štruktúry vrátiť chybový stav - ak sa však konštruktor ešte predtým nepostará o upratanie tých častí pamäte ktoré sa mu allokovať podarilo, budú ich adresy nenávratne zabudnuté a nikomu sa ich už nepodarí po celú dobu behu programu uvoľniť.
Line 77: Line 171:
   a. Ak deklarujete napríklad `int pole[n]` kde `n` je nejaká predtým inicializovaná premenná, devcpp, žial, nebude frflať. Lenže niečo podobné je z hladiska čistého ANSI C striktne zakázané. Keďže hodnota `n` nie je v čase kompilácie známa, to čo takouto deklaráciou hovoríte, je vlastne dynamická allokácia pamate. Ale tá sa správne rieši cez funkciu `malloc` a jej príbuzné. Jediný dôvod prečo takýto riadok ide skompilovať je to, že devcpp nie je dôsledný kompilátor a, aj bez toho aby o to bol požiadaný, do jazyka mieša črty neoficiálnych rozšírení a C++. Ja ale takéto tolerovať nebudem; skúste to skompilovať pod linuxom pomocou `gcc` a hneď pochopíte prečo.    a. Ak deklarujete napríklad `int pole[n]` kde `n` je nejaká predtým inicializovaná premenná, devcpp, žial, nebude frflať. Lenže niečo podobné je z hladiska čistého ANSI C striktne zakázané. Keďže hodnota `n` nie je v čase kompilácie známa, to čo takouto deklaráciou hovoríte, je vlastne dynamická allokácia pamate. Ale tá sa správne rieši cez funkciu `malloc` a jej príbuzné.
Line 87: Line 181:
  a. Všetky deklarácie lokálnych premenných sa vybavia na začiatku tela funkcie. Dalej nasleduje už iba kód, žiadne prípadné ďalšie deklarácie.
Line 89: Line 184:
  a. Pri funkciach sa explicitne uvadza datovy typ a navratovy typ aj vtedy, ak tieto nemaju argumenty alebo ziadnu hodnotu nevracaju. Prečo? Dáva nám to dopredu vedieť, čo možno od tej ktorej funkcie očakávať, čo opäť sprehľadňuje zdroják.
Line 131: Line 227:
        if(i < 0)
                i = -i;

        do{
                i--;
                printf(".");
        }while(i!=1)

        /* aj jednoriadkovy blok je blok */
        if(i>0)
                if(j<0)
                        j=i;
        else
                if(j>0)
                        i=j;

Organizačné informácie

Pre ich citlivú povahu budem uvádzať v systéme anjadu.

Štúdijné materiály

Slajdy k prednáškam

Iné zdroje

Mercurial: Varíme z ortuti - zdravo, rýchlo, lacno

Mercurial: Quick Start

Mercurial: The Definitive Guide

Mercurial: Návod v českom jazyku

Časté chyby

Každodenná programátorská skúsenosť aj vás naučí, že čitateľnosť a zrozumiteľnosť zdrojáku je nie len nutnou podmienkou jeho trvalej spravovateľnosti ale aj cestou k zachovaniu psychyckého zdravia - ako vašeho tak aj môjho. Na užitočnosť štábnej kultúry prišli už naši predkovia, ktorí stáli pri kolíske programovacích jazykov. Budeme sa toho držať aj my. Toto je zoznam pravidiel, ktorých splnenie bude nutnou podmienkou k tomu, aby som vaše zdrojáky vôbec študoval. Preto vám radím, aby ste sa ich snažili dodržiavať už od prvého zadania.

  1. Chyby týkajúce sa designu funkcií
    1. Každá jedna funkcia alebo procedúra má vykonávať jednu, čo možno najjednoduchšiu činnosť a túto činnosť má vykonávať dobre. Áno, existujú výnimky z tohoto pravidla, ale na tomto seminári sa s nimi nestretneme.

    2. Rozmeniac na drobné predchádzajúci bod: ak žiadam implementáciu funkcie ktorá vykonáva činnosť Č tak tým myslím, bez toho aby som to explicitne zdôraznoval, že funkcia žiadnu inú činnosť nevykonáva. Napríklad ak chcem, aby funkcia inicializovala pole premenných typu int na zadanú hodnotu $h$ tak, bez toho aby som to explicitne písal, očakávam, že funkcia nebude ani nič čítať z klávesnice, ani nič písať na obrazovku a vôbec, nebude robiť nič čo bezprostredne nesúvisí s inicializáciou pola.

    3. Veľké datové typy a komplikované datové štruktúry sa funkciám nikdy neodovzdávajú ako argumenty. Namieto toho sa ako argumenty odovdávajú iba smerníky na ne. Prečo? Na prednáške sa dozviete, že každé odovzdanie argumentu funkcii pri jej volaní obnáša kopírovanie hodnôt argumentov. Jazyk C toto kopírovanie zakrýva ale to neznamená, že k nemu nedochádza. Ak sú argumentami funkcie nejaké veľké štruktúry, znamená to veľa kopírovania a to je neefektívne. Naproti tomu smerník je iba jedno relatívne malé číslo a to sa kopíruje ľahko.

    4. Funkcie vymýšlajte tak, aby referovali všetky možné typy chybových stavov ktoré pri ich vykonávaní môžu nastať. Príznaky týchto chybových stavov referujú primárne cez návratovú hodnotu a ak len ak sa to nedá nejak inak.
    5. Zásada o pred-objektovej disciplíne: Všetky "konštruktory" (čiže funkcie, ktoré sa starajú o allokáciu pamäte pre komplikované datové štruktúry) allokujú celé datové štruktúry a volajúcemu procesu cez navratovu hodnotu odovzdávajú iba ich adresy. Všetky "deštruktory" (čiže funkcie, ktoré sa starajú o uvoľnovanie pamäte po komplikovaných datových štruktúrach) uvoľňujú pamäť po celých datových štruktúrach a ako argument preberajú iba smerník na štruktúru ktorú treba zničiť.

    6. Všetky "konštruktory" (čiže funkcie, ktoré sa starajú o allokáciu pamäte pre komplikované datové štruktúry) treba implementovať tak, aby v prípade keď sa proces allokacie pamäte nepodarí z nejakého dôvodu úspešne zavŕšiť, uvolnili tie časti pamäte ktoré sa im ešte pred nastaním problému allokovať podarilo. Motivácia pre túto zásadu je úplne jasná: kedykoľvek proces allokácie niekde uviazne, treba volajúcemu procesu namiesto allokovanej štruktúry vrátiť chybový stav - ak sa však konštruktor ešte predtým nepostará o upratanie tých častí pamäte ktoré sa mu allokovať podarilo, budú ich adresy nenávratne zabudnuté a nikomu sa ich už nepodarí po celú dobu behu programu uvoľniť.
  2. Črty jazyka ktoré nepatria do ANSI C
    1. Ak deklarujete napríklad int pole[n] kde n je nejaká predtým inicializovaná premenná, devcpp, žial, nebude frflať. Lenže niečo podobné je z hladiska čistého ANSI C striktne zakázané. Keďže hodnota n nie je v čase kompilácie známa, to čo takouto deklaráciou hovoríte, je vlastne dynamická allokácia pamate. Ale tá sa správne rieši cez funkciu malloc a jej príbuzné.

  3. Programátorský štýl
    1. Blok kódu začína vždy na novom riadku. Aj v prípade, že sám nemá viac než jeden riadok. Prečo? Už z letmého pohladu na zdroják je jasné aké panujú medzi časťami kódu logické vzťahy.

    2. Blok kódu je oproti okolitému kódu odsadený o jeden tabulátor doprava. Prečo? Už z letmého pohladu na zdroják je jasné, kde blok kódu začína a kde končí.
    3. Mená symbolických konštánt sa píšu vždy veľkými písmenami. Prečo? Táto jednoduchá konvencia ktorá programátora prakticky nič nestojí umožnuje už letmým pohladom odlíšiť symbolické konštanty od premenných, čo je viac než užitočné.
    4. Návratové chybové stavy funkcií sa realizujú ako symbolické konštanty. Prečo? Pri letmom pohlade na kondicionál
      • if(sucet(argumenty1, argumentyn) == 1)

      by sa mohlo zdať, že testujeme, či sa výsledok nejakého výpočtu (ktorý realizuje funkcia sucet) náhodou nerovná jednej. Ak ale čítame

      • if(sucet(argumenty1, argumentyn) == PROBLEM_PRETECENIE_ROZSAHU_INT)

      je nám okamžite jasné, že je to test na chybový stav. To, samozrejme, nesmierne sprehľadňuje zdrojový kód.
    5. Všetky deklarácie lokálnych premenných sa vybavia na začiatku tela funkcie. Dalej nasleduje už iba kód, žiadne prípadné ďalšie deklarácie.
    6. Medzi deklarácie premenných na začiatku tela funkcie a jeho zvyšok sa vkladá prázdny riadok. Prečo? Programátor čítajúci zdrojový kód preskakuje deklarácie premenných a vracia sa k nim až neskôr, keď sa chce dozvedieť akého typu tá ktorá premenná je. Prázdny riadok na konci deklarácií výrazne ulahčuje takýto spôsob čítania zdrojáku.
    7. Medzi definíciami funkcií ako aj medzi inštrukciami preprocesora na začiatku zdrojového kódu a kódom samotným sa nachádzajú voľné riadky. Prečo? Opticky to oddeluje veci ktoré spolu súvisia od vecí ktore spolu nesúvisia čo, opäť, zvyšuje čitateľnosť kódu.
    8. Pri funkciach sa explicitne uvadza datovy typ a navratovy typ aj vtedy, ak tieto nemaju argumenty alebo ziadnu hodnotu nevracaju. Prečo? Dáva nám to dopredu vedieť, čo možno od tej ktorej funkcie očakávať, čo opäť sprehľadňuje zdroják.

Ukážkový Zdroják

   1 #include <stdlib.h>
   2 #include <stdio.h>
   3 
   4 void print_num(int a)
   5 {
   6         printf("%d",a);
   7 }
   8 
   9 int main(void)
  10 {
  11         int i, j, k;
  12         char *string;
  13         double ratio;
  14 
  15         /* nadomnou je volny riadok oddelujuci deklaracie (zasada 3.e) */
  16         if(i == j)
  17                 printf("Premenne i a j maju, zhodou okolnosti, rovnaku hodnotu.\n");
  18         else {
  19                 printf("Premenne i a j maju, zhodou okolnosti, roznu hodnotu.\n");
  20                 print_num(i);
  21                 print_num(j);
  22         }
  23 
  24         if(&i == (int*)string) {
  25                 printf("tento kod sa NIKDY nevykona.");
  26                 i = j+k;
  27                 j = i-k;
  28         }
  29 
  30         for(i=0;;i++)
  31                 if(i != k) {
  32                         printf(".");
  33                         k -= i;
  34                 } else {
  35                         printf("zaverecna");
  36                         break;
  37                 }
  38 
  39         if(i < 0)
  40                 i = -i;
  41 
  42         do{
  43                 i--;
  44                 printf(".");
  45         }while(i!=1)
  46 
  47         /* aj jednoriadkovy blok je blok */
  48         if(i>0)
  49                 if(j<0)
  50                         j=i;
  51         else
  52                 if(j>0)
  53                         i=j;
  54 
  55         /* dovidenia */
  56         return(0);
  57 }

KMaDGWiki: KurzSeminarZProgramovania (last edited 2019-01-28 14:51:18 by sarkoci)