[[PageOutline]] = Vaje programiranja v jeziku C = Znanje programskega jezika C najlažje pridobimo z vajo. Namen domačih nalog predstavljenih na tej strani je predvsem utrditi določene programske konstrukte, ki se lahko rešijo v krajših programih, katere pravilnost delovanja ni težko preveriti. Naloge se izdelujejo z orodji, ki so predvidene za izdelavo projekta. To pomeni, da je vsako vsako vajo, ki jo izdelujemo najprej preveriti na lokalnem računalniku. Ko je možno izdelati nalogo št. ??? z ukazom {{{ make vaja??? }}} je vaja??? primerna za shranitev na strežnik, kar naredimo z ukazi '''svn'''. Ker so naloge enostavne, lahko v datoteko {{{Makefile}}} napišemo naslednje implicitne definicije in se s tem izognemo pisanju eksplicitnih ukazov. Dovolj je že če na začetek Makefile napišemo: {{{ CFLAGS = -Wall LDFLAGS = -lm }}} in večina nalog bo izdelana z ukazom make vaja???, kjer namesto ?? napišemo številko naloge. Pravilnost vaših nalog lahko tudi sami preverite z [http://lecad.si/cgi-bin/cclass.cgi Ocenjevalcem nalog], ki izvede test delovanja s tem da vajo prevede, pregleda izvorno kodo in požene kontrolni test. Pri kontroli delovanja je možno, da ocenjevalec javi daj program ne deluje pravilno. Če pa menite, da Vaš program deluje pravilno, je možno da je kontrolni test napačen ali pa besedilo vaje ni dovolj jasno. V tem primeru odprite [http://lecad.si:8000/vaje/newticket Nov Listek] in opišite težavo. Izdelane vaje morajo pravilno delovati, kar preverjamo z [http://lecad.si/cgi-bin/cclass.cgi Ocenjevalcem nalog]. V primeru, da vaja ne prestane testa, ne bo upoštevana kot narejena. Zaželjeno je tudi, da naredimo čim več vaj, ni pa potrebno izdelati več kot je zahtevano. Prvi dve vaji, ki smo jih naredili v laboratoriju, je potrebno preveriti in morebiti popraviti, da delujeta pravilno. = Vprašanja za utrjevanje = 1. Zakaj je potrebno napisati vrstico {{{#include }}} 1. Kako uporabljamo komentarje? 1. Zakaj je zamikanje stavkov pomembno? Ali prevajalnik upošteva zamikanje? 1. Koliko decimalk hrani tip {{{int, float}}} in {{{double}}}? 1. Kakšna je razlika pri prireditvi konstante spremenljivkama '''c''' in '''d''' {{{ #!c float c = 3/2; float d = 3.0/2; }}} 1. Kaj je funkcija podpičja v stavku? Naštej kje vse ga je potrebno uporabiti. 1. Koliko je numerična vrednost naslednjega izraza {{{ #!c int i = 5 < 6; }}} 1. Pod katerimi pogoji naslednja koda izpiše '''voda'''? Kako bi jasneje napisali napisane pogojne stavke z uporabo zavitih oklepajev in primernejšega zamikanja? {{{ #!c if(temp < 0) printf("led\n"); else if (temp < 100) printf("voda\n"); else printf("para\n"); }}} 1. Kaj izpiše naslednja koda? {{{ #!c int x = 3; if (x) printf("da\n"); else printf("ne\n"); }}} 1. Kaj bo izpisala naslednja koda? {{{ #!c int i; for(i = 0; i < 3; i++) printf("a\n"); printf("b\n"); printf("c\n"); }}} 1. Koliko elementov vsebuje polje oz. vektor '''a'''? Kateri je prvi element? Kateri je zadnji? {{{ #!c int a[5]; }}} 1. Kaj je narobe v naslednjem izvlečku kode? {{{ #!c int a[5]; for(i = 1; i <= 5; i = i + 1) a[i] = 0; }}} 1. Kateri so štirje pomembni deli funkcije? Katere tri mora klicoči program poznati? 1. Kakšna je razlika med ''prefix'' in ''postfix'' operatorjem ++. Kakšna je razlika med naslednjima izrazoma: {{{ #!c r = i++; r = ++i; }}} 1. Kaj je narobe z naslednjim predprocesorskim izrazom? {{{ #!c #define N 10; }}} 1. Če smo na primer definirali makro {{{ #!rst .. code-block:: c #define SQR(x) x*x Zakaj nam potem izraz .. code-block:: c y = 1/SQR(x); ne deluje pravilno? Kako bi morali pravilno napisati makro SQR(x), da bi delal tudi za izraze .. code-block:: c y = 1/SQR(1-x); }}} 1. Kakšna je razlika v uporabnosti med '''i''' in '''J''', ki sta napisana kot {{{ #!rst .. code-block:: c int i = 10; #define J 10 Napotek: Poskusi napisati ``J = 2`` ali ``int a[i]``. }}} 1. Zakaj je potrebno v {{{scanf()}}} argumente za formatnim stavkom pisati z &, pri {{{printf()}}} pa tega ne smemo? 1. Koliko spomina klic {{{ #!rst .. code-block:: c malloc(10) alocira? Kaj moramo napisati če želimo alocirati spomin za 10 spremenljivk tipa float? }}} 1. Kaj mislimo z ''enakostjo med polji in kazalci'' v C-ju? 1. Če je {{{p}}} kazalec, kaj potem pomeni {{{p[i]}}}? 1. Kako odpiramo datoteko za branje podatkov iz nje? Kaj se spremeni, če bi datoteko želeli odpreti za pisanje? = Uporaba zank in izpis = {{{ #!comment http://www.eskimo.com/~scs/cclass/asgn.beg/PS1.html }}} == vaja1 == Napiši program, ki zahteva vnos dveh celih številk in nato izpiše njihovo vsoto. == vaja2 == Gaussovo kvadratura naj vpraša za meji integriranja funkcije f(x) = 2x^4^- x^3^ +1 in rezultat izpiše na zaslon. == vaja3 == Izdelaj program ki izpiše naslednje zanke: {{{ #!c for(i = 0; i < 10; i = i + 2) printf("%d\n", i); for(i = 100; i >= 0; i = i - 7) printf("%d\n", i); for(i = 1; i <= 10; i = i + 1) printf("%d\n", i); for(i = 2; i < 100; i = i * 2) printf("%d\n", i); }}} Razjasni si, kako te zanke delujejo in program popravi tako, da bodo v zanki uporabljeni operatorji +=, -=, *= == vaja4 == Napiši program ki izpiše ta trikotnik: {{{ * ** *** **** ***** ****** ******* ******** ********* ********** }}} Ne uporabi desetih printf() ampak uporabi zanko. {{{ #!c for(i = 0; i < 10; i = i + 1) { /* Več stavkov */ /* gre lahko tukaj */ } }}} == vaja5 == Izpiši v zanki cela števila od 1 do 10 in njihove kvadrate. {{{ 1 1 2 4 3 9 ... 10 100 }}} == vaja6 == Stavek '''for''' je prav zaprav, okrajšava za stavek '''while'''. Predelaj program, ki izpiše naslednjo zanko: {{{ #!c for(i = 0; i < 10; i = i + 1) printf("i je %d\n", i); }}} z uporabo stavka '''while''', ki ima naslednjo obliko {{{ #!c while(pogoj) { /* vpiši stavek za povečanje števca in izpis */ } }}} Napotek: V primeru da se nam program ''obesi'' v neskončni zanki, ga prekinemo s pritiskom na crtl-C == vaja7 == Pretipkaj in poženi naslednji program: {{{ #!c #include int main() { int i; printf("stavek 1\n"); printf("stavek 2\n"); for(i = 0; i < 10; i = i + 1) { printf("stavek 3\n"); printf("stavek 4\n"); } printf("stavek 5\n"); return 0; } }}} Program ne naredi nič posebnega. Z njim želimo le pojasniti vpliv zavitih oklepajev v zanki in dobiti željen ''potek programa''. == vaja8 == Pretipkaj in poženi naslednji program: {{{ #!c #include int main() { int i, j; printf("začetek programa\n"); for(i = 0; i < 3; ++i) { printf("i je %d\n", i); for(j = 0; j < 5; j++) printf("i je %d, j je %d\n", i, j); printf("konec v zanki i = %d\n", i); } printf("konec programa\n"); return 0; } }}} Tudi ta program ne naredi kaj dosti koristnega. Želi pokazati, kako zanke delujejo in kako jih ''gnezdimo''. V vaji 4 je potrebno uporabiti prikazani način dvojne zanke. == vaja9 == Program naj prebere štiri cele številke in izpiše povprečno vrednost kot realno številko. == vaja10 == Program naj prebere vrednost x, izračuna kvadrat prebranega števila (x^2^) in ga izpiše na zaslon. Izdelaj podprogram sqr(x). == vaja11 == Program naj prebere vrednost x in n, kot celi števili. Izdelaj podprogram power(x, n), ki izračuna n to potenco števila x in jo izpiše na zaslon. = Pogojni stavek in zahtevnejše zanke = == vaja20 == Napiši program, ki z zanko in pogojnim stavkom ugotovi, koliko števil od 1 do 10 je večjih od 3 in seveda izpiše rezultat 7. == vaja11 == Program naj poleg številk od 1 do 20 izpiše še ali je liha ali soda v obliki {{{ #!rst .. code-block:: c 1 je liha 2 je soda 3 je liha ... Napotek: Uporabi operator ``%`` }}} == vaja21 == Izdelaj program, ki izpiše v katero smer se je 2D točka največ premaknila, glede na koordinatno izhodišče. Možni odgovori so: - levo - desno - gor - dol Za prebrano točko 2 1 bo program odgovoril ''desno''. == vaja23 == Tako kot v vaji 12 naj dodatno še izpiše v kater smer se je premaknila. S tem da se najprej izpiše večji pomik in nato manjši. Za prebrano točko 2 1 bo program odgovoril {{{desno gor}}}. == vaja24 == Napiši program, ki izpiše prvih 7 pozitivnih števil in njihovo faktorielo (fakulteto). (Faktoriela 1 je 1, faktoriela 2 je 1*2=2, faktoriela 3 je 1 * 2 * 3 = 6, faktoriela 4 je 1 * 2 * 3 * 4 = 24, itd.) == vaja25 == Program naj izračuna prvih 30 [http://sl.wikipedia.org/wiki/Fibonaccijevo_%C5%A1tevilo Fibonaccijevih števil]. Vsaka Fibonaccijeva številka je vsota prejšnjih dveh števil F(n) = F(n-1) + F(n-2), F(0) = 0, F(1) = 1. Izpis naj bo v obliki: {{{ 0 + 1 = 1 1 + 2 = 3 2 + 3 = 5 ... }}} == vaja26 == Napiši program ji za podano število izpiše {{{je praštevilo}}} ali {{{ni praštevilo}}}. [http://sl.wikipedia.org/wiki/Pra%C5%A1tevilo Práštevílo] je naravno število n > 1, če ima natanko dva pozitivna delitelja (faktorja), število 1 in samega sebe kot edini prafaktor. == vaja27 == Pohitri {{{vaja16}}} z dejstvom, da razen 2 nobeno sodo število ni praštevilo. Glej vajo 11. == vaja28 == Napiši program, ki tabelira poštevanko od 1 do 10, tako da izpiše vse skupaj v 10 vrsticah v obliki: {{{ 1*1=1 1*2=2 1*3=3 ... 10*1=1 10*2=20 ... }}} = Nizi, vektorji, matrike = == vaja40 == Program iz vaje 18 priredi tako, da bo se zmnožek najprej predizračunal v polje {{{ #!rst .. code-block:: c int a[100]; in na to naj program vpraša za dve števili, ter izpiše rezultat, ki ga vzame iz polja ``a[]``. }}} == vaja41 == Napiši program ki bo v polje števil nadomesitil z njihovnimi kvadrati. Program naj vpraša kateri indeks iz polja želimo in naj izpiše vrednost v polju. S stavkom if mora tudi kontrolirati meje indeksov. {{{ #!c int a[] = {1, 2, 9, 33, 22, 11, 3, 4, 3, 55, 66, 33, 22, 22, 33, 54, 5, 6, 7, 8, 223, 34}; }}} == vaja42 == Za podano kvadratno matriko {{{a[16]}}} in vektor {{{x[4]}}} {{{ #!rst .. code-block:: c float a[16] = {1, 2, 3, 4, 0, 1, 2, 3, 2, 3, 4, 5, 3, 2, 2, 1}; float x[4], b[4]; napiši program, ki prebere štiri vrednosti in izpiše zmnožek matrike in vektorja s stavkom .. code-block:: c printf("%.1f %.1f %.1f %.1f\n", b[0], b[1], b[2], b[3]); }}} == vaja43 == Programa naj prebere datoteko, ki je podobna tisti na vajah, le da ima na začetku napisano še številko vrstice, ki pa nas ne zanima. {{{ 1 8 1 2 00 00 06 00 0 3 06 00 14 00 -1 4 14 00 20 00 0 5 20 00 20 10 0 6 20 10 14 10 0 7 14 10 06 10 1 8 06 10 00 10 0 9 00 10 00 00 0 }}} Datoteko preberite v spremenljivke {{{ #!c #define MAXN 100 float p0[MAXN*2], p1[MAXN*2], q[MAXN]; int n, div; }}} in vsako vrstico v zanki izpišite z naslednjim formatnim stavkom: {{{ #!c printf("%4.1f %4.1f %4.1f %4.1f %4.1f\n", ... }}} prve in druge točke elementa ter q. == vaja44 == Za podano kvadratno matriko {{{A[]}}} zmanjšaj diagonalne elemente za vrednost 1 in spremenjene diagonalne elemente matrike {{{A}}} s pomočjo for zanke izpiši na zaslon . {{{ #!c float A[25] = {3, 5, 90, 2 ,1, 1, 71, 59, 5, 5, 1, 2, 3, 54, 2, 12, 56, 32, 11, 1, 34, 56, 78, 45, 12 }; }}} == vaja45 == Polje {{{a[]}}} iz vaje 41 prepišite v matriko {{{float b[]}}} velikost 8x3. S tem sa so elementi, ki manjkajo postavljeni na 0. Vrstice izpišite na eno decimalko natančno. == vaja46 == Za podano kvadratno matriko {{{A[5][5]}}} zmanjšaj diagonalne elemente za vrednost 1.1, pre piši dvidimenzionalno polje A v enodimenzionalno polje B, ki ga računamo kot matriko 5x5 izpišemo z dvojno zanko na zaslon. {{{ float A[5][5] = {{3.3, 5.2, 90.5, 2.3 ,1.1}, {1.9, 71.0, 59.5, 5.3, 5.5}, {1.0, 2.2, 3.5, 54, 2}, {12.4, 56.1, 32.2, 11.4, 1.6}, {34.8, 56.4, 78.9, 45.3, 12.3} }; }}} = Podprogrami = == vaja60 == Predelajte program za množenje matrike z vektorjem iz vaje 21, tako da boste pred izpisom uporabili klic podprograma s stavkom {{{ #!c mat_vec4(b, a, x); printf("%.1f %.1f %.1f %.1f\n", b[0], b[1], b[2], b[3]); }}} == vaja61 == Predelajte program vaje4 tako, da boste napisali podprogram, ki ga boste klicali v naslednji zanki {{{ #!c for(i = 0; i < 10; i++) print_stars(i); }}} == vaja62 == Napišite podprogram {{{float celsius(float fahrenheit)}}}, ki pretvori Fahrenheitove stopinje v Celsiusove. Formula za pretvorbo je °C = 5/9 * (°F - 32). Program naj naprej vpraša za stopinje F in nato na decimalko natačno izpiše vrednost v Celzija. Zapomnite si, da celoštevilčni izraz 5/9 da rezultat 0, zato ne smete uporabiti celoštevilčnega deljenja. == vaja63 == Stavek {{{ r = rand()*N/RAND_MAX + 1 }}} vrne naključno številko med 1 in N. Izdelajte program, ki simulira metanje kocke. Izdelajte program, ki simulira zaporedno metanje dveh kock in izriše histogram za 100 metov v (približno) taki obliki: {{{ #!rst :: 2: 2 ** 3: 5 ***** 4: 4 **** 5: 10 ********** 6: 15 *************** 7: 28 **************************** 8: 12 ************ 9: 9 ********* 10: 7 ******* 11: 5 ***** 12: 3 *** Prva številka pomeni vsoto pik na obeh kockah, druga številka pa pomeni koliko krat se je dogodek zgodil, kar je tudi grafično narisano z podprogramom iz vaje 23. Napotek: Pogled v navodila za funkcijo rand vam bo razkril, da je potrebno vklučiti header ```` in povezovati z ``-lc``. }}} == vaja64 == Izdelajte podprogram za linearno interpolacijo. Program naj vpraša za dve točki (x,,0,,,y,,0,,) in (x,,1,,,y,,1,,) ter mesto na osi ''x'' za katero želimo vrednost ''y''. Npr. za {{{ 0 0 1 1 0.5 }}} mora vrniti 0.5. Podprogram naj ima naslednji prototip: {{{ #!c float linear_interpolation(float x, float p0[2], float p1[2]) }}} == vaja65 == Podprogram za parametrizacijo daljice naj izpiše koordinato glede na parameter ''t'', ki je v mejah od 0 do 1. Podobno kot pri vaji 64 preberemo točki (x,,0,,,y,,0,,) in (x,,1,,,y,,1,,) in parameter ''t''. Prototip {{{ #!c void linear_interpolation(float t, float p0[2], float p1[2]) }}} naj izpiše točko s formatom "%.1f %.1f". Prednost parametrične interpolacije je v tem, da deluje tudi za navpično daljico. Npr. {{{ 0 0 0 2 0.5 }}} vrne 0.0 0.5 Ko je parameter t=0 se izpiše začetna točka. Pri t=1 pa končna. == vaja66 == Podobno kot v vaji 65 izdelajte podprogram, ki za parameter t v mejah od -1 do 1 izpiše točko med podanima točkama. Ko je parameter t=-1 se izpiše začetna točka. Pri t=1 pa končna. Za t=0 se izpiše točka na sredini. = Dinamična alokacija spomina in delo z datotekami = == vaja80 == Program naj prebere datoteko '''vaja80.dat''', ki vsebuje seznam celih številk in izpiše njihovo vsoto. V prvi vrstici je število celih števil ki sledijo v naslednjih vrsticah. Primer: {{{ 4 13 23 21 11 }}} Za ta primer mora program izpisati 72. Število vrstic v datoteki {{{vaja80.dat}}} je lahko največ 100. == vaja81 == Podobno kot v vaji 80 preberite datoteko '''vaja81.dat''' s tem da števila niso več omejena z velikostjo polja ampak ga dinamično alocirajte z {{{malloc()}}} po tem, ko bo prebrana prva vrstica. == vaja82 == Preberi datoteko {{{vaja82.dat}}} v kateri sta zaporedno zapisani dve 4x4 matriki. Na primer: {{{ 1 2 3 4 5 6 7 8 9 0 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 2 5 6 }}} Program naj datoteko prebere in vpraša za kateri i-ti in j-ti naj naredi seštevek. Seštevek naj izpiše na zaslon. Na primer za i=1 in j=3 mora izpisati 9. == vaja83 == Program naj prebere iz datoteke '''vaja83.dat''' matriko velikosti ixj in izpiše element {2, 3}. Format datoteke je {{{ 4 5 1 2 3 4 5 4 5 5 6 6 4 4 4 99 4 6 7 7 8 1 }}} V prvi vrstici piše število vrstic in število kolon matrike. Izpisal pa bi 99. == vaja84 == Matriko iz tako kot pri vaji 83 preberemo iz datoteke '''vaja84.dat''' in izpišemo v transponirani obliki kot cela števila. Matriko celih števil dinamično alocirajte z malloc. == vaja85 == Matriko iz tako kot pri vaji 83 preberemo iz datoteke '''vaja85.dat''' in Vse elemente matrike kvadriramo in zapišemo v datoteko '''vaja85.rez''', v istem formatu celih števil. = Aplikacije = == vaja100 == Izračunaj faktor Učinkovite Rabe Energije, tako kot ga podaja [http://www.elektro-ljubljana.si/slo/Ceniki Elektro Ljubljana]. Dobavitelj v ceniku za vsak '''razred porabe''' določi '''faktor cene energije''', ki je osnova za izračun faktorja URE po naslednji enačbi: URE = ∑(E,,i,, F,,CE i,,)/E,,povprečna dnevna poraba,, Tabela razredov porabe in pripadajočimi faktorji cene električne energije] ima 5 razredov s progresivno stopnjo F,,CE,, ||Razred porabe||Povprečna dnevna poraba energije (E,,i,,)||Faktor cene energije (F,,CE,,)|| ||1.razred||do 6 kWh dnevne porabe||1.0|| ||2.razred||nad 6 do vključno 12 kWh dnevne porabe||1.1|| ||3.razred||nad 12 do vključno 18 kWh dnevne porabe||1.3|| ||4.razred||nad 18 do vključno 24 kWh dnevne porabe||1.5|| ||5.razred||nad 24 kWh dnevne porabe||2.0|| Na primer URE za 8kWh dnevne porabe izračunamo kot URE=(6*1.0-(8-6)*1.1)/8 Tabela[http://www.elektro-ljubljana.si/_services/document.php?name=ure__faktorji_uinkovite_rabe_energije_za_posamezno_povpreno_dnevno_porabo.pdf&langId=Slo&pageId=89 URE Faktorjev učinkovite rabe energije za posamezno povprečno dnevno porabo], se računajo samo za celoštevilčni del povprečne dnevne porabe. Izdelaj program, ki za vnešeno realno povprečno porabo izpiše faktor URE v formatu, kot je v pred izračunani tabeli. Napotek: Za izračun celega dela realnega števila uporabite funkcijo '''floor'''. == vaja101 == Ceno za uporabo omrežij določa Akt o določitvi metodologije za obračunavanje omrežnine in metodologije za določitev omrežnine in kriterijih za ugotavljanje upravičenih stroškov za elektroenergetska omrežja, (Ur.l. RS 121/2005) in je sestavljena iz: - stalnega mesečnega prispevka za moč, ki zanaša 0,66179 €/kW/mesec - cene za prenešeno delovno energijo, ki znaša: * v primeru dvotarifnega načina merjenja porabe električne energije: {{{ VT: 0,03731 €/kWh MT: 0,02924 €/kWh }}} * v primeru enotarifnega načina merjenja porabe električne energije: {{{ ET: 0,03462 €/kWh }}} Izdelaj program, ki uporabnik vpraša po predvidenem mesečnem številu kWh VT in NT in izpiše ceno za prenešeno delovno energijo v primeru dvotarifnega in v primeru enotarfnega načina merjenja porabe električne energije. Uporabniku naj glede na vnešena podatka program svetuje, kateri način je zanj najbolj primeren. == vaja102 == Če ste izdelali vajo 100 in 101, potem združite programa v vaji 102 tako, da izračunate kako bo z elektriko po novem sistemu z URE faktorjem. Obračun porabljene električne energije na podlagi izračunanega faktorja URE se izvede tako, da se pomnoži količina električne energije v posamezni tarifi, s ceno električne energije v tej tarifi in z izračunanim odjemalčefim faktorjem URE. Upoštevajte, da ima mesec 31 dni. Program pa naj tako kot v vaji 11 vpraša za število kWh v visoki in nizki tarifi, izpiše posamezne cene ter svetuje najprimernejši način tarifiranja. {{{ #!comment == vaja103 == Program za praštevila iz vaje 16 in 17 lahko pohitrimo z dejstvom, da si lahko privarčujemo čas tako, da v polju {{{int a[N]}}} hranimo praštevila na katera smo do sedaj naleteli. Če je število deljivo s praštevilom iz tabele, potem to ni praštevilo. Lahko pasi naredimo tudi sito, ki }}} = Grafični jezik OpenGL =