815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 4 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten lauseisiin, lausekkeisiin ja aliohjelmiin liittyvät kysymykset. Tehtävä 1. Mitä seuraava C-ohjelma tulostaa ja miksi? Yritä ensin päätellä ja testaa suorittamalla ohjelma. #include <stdio.h> int tuplaa (int *luku) *luku *= 2; return *luku; int main() int a = 5,x; int *ptr = &a; x = tuplaa(ptr) + *ptr; printf("x = %d\n",x); return 0; Muuttuuko tulostus, jos pääohjelma muutetaan muotoon int main() int a = 5,x; int *ptr = &a; x = *ptr + tuplaa(ptr); printf("x = %d\n",x); return 0; Miksi tai miksi ei? Vastaus. Muuttujaan x sijoitettava arvo riippuu siitä, missä järjestyksessä lauseke tuplaa(ptr) + *ptr evaluoidaan. Funktio kertoo kahdella osoitinparametrinsa osoittaman muistiosoitteen sisällön ja palauttaa kaksinkertaistetun arvon. Näin ollen muuttujan a arvo 5 kerrotaan kahdella ja palautetaan arvo 10. Funktion kutsun jälkeen muistipaikassa on arvo 10. Mikäli funktio suoritetaan ennen arvon *ptr evaluointia, muuttujan x arvoksi tulee 10 + 10 = 20. Jos taas evaluoidaan ennen funktion kutsua, muuttujan x arvoksi tulee 10 + 5 = 15. C-kielen standardi ei (ainakaan luennoitsijan tietojen mukaan) määrää mikä on lausekkeen evaluointijärjestys. Harjoitusluokassa testattaessa (Dev-C++) saatiin arvo 20, mutta tulos voi periaatteessa vaihtua toisella kääntäjällä. Kun vaihdetaan sijoitettava lauseke muotoon *ptr + tuplaa(ptr), luokan ympäristössä tulos säilyy samana, joten funktio evaluoidaan ensin. Sen sijaan
luennoitsijan gcc-kääntäjän versio 4.9.1 vaihtaa evaluointijärjestyksen niin, että *ptr evaluoidaan ennen funktion kutsua, jolloin muuttujan x arvoksi tulee 15. Tehtävä 2. Olkoon C-ohjelmassa kokonaislukumuuttujilla a,b,c ja d arvot a = 5 b = 29 c = 3 d = 6 ja bool-tyyppisillä muuttujilla x,y ja z arvot x = true y = false z = true Käyttääksesi bool-tyypin muuttujaa on sinun sisällytettävä otsikkotiedosto <stdbool.h> ja kääntämällä C-kielen versiolla C99 (tai uudemmalla). Päättele ensin lausekkeiden 1. a + b/c %d 2. -a + ++b /d 3. a*2 + b++ /d 4.!x y && z arvot ja testaa ohjelmalla päättelitkö oikein. Vastaus. Lausekkeiden arvot riippuvat operaattoreiden suoritusjärjestyksestä eli presedenssistä. Huomioi, että muuttujat ovat kokonaislukutyyppisiä, joten niiden jakolaskun tulos on myös kokonaisluku. Huomaa myös, että operaattori ++ on lausekkeessa 2 prefix-muodossa, jolloin se evaluoidaan ensimmäiseksi, ja lausekkeessa 2 postfix-muodossa, jolloin se evaluoidaan vasta lausekkeen muun evaluoinnin jälkeen. Lauseke 1 evaluoidaan järjestyksessä b/c = 9 % d = 3 ja a+3 = 8 Lauseke 2 evaluoidaan järjestyksessä ++b = 30, -a = -5, 30/d = 5 ja -5+5 = 0 Lauseke 3 evaluoidaan järjestyksessä a*2 = 10, b/d = 4 ja 10+4 = 14. Suorituksen jälkeen muuttujan b arvo on 30, mutta postfixinä se tehdään vasta lausekkeen evaluoinnin jälkeen. Lauseke 4 evaluoidaan järjestyksessä!x = false, y&& z = false ja false false = false Nämä tulokset voi varmistaa kirjoittamalla yksinkertainen ohjelma, jossa arvot lasketaan. Muista palauttaa muuttujan b arvo toisen lausekkeen suorittamisen jälkeen.
Tehtävä 3. Kirjoita ohjelma, jonka avulla voi päätellä, käytetäänkö C-kielessä loogisten lausekkeiden oikosulkuevaluointia. Vastaus. Loogisen lausekkeen oikosulkuevaluointi tarkoittaa sitä, että lausekkeen kaikkia komponentteja ei evaluoida, mikäli lausekkeen totuusarvo tiedetään jo aiemmin. Esimerkiksi laskettaessa kahden lausekkeen loogista and-operaatiota, lopputulos on aina toisesta lausekkeesta riippumatta false, jos ensimmäisen lauseen totuusarvo on false. Samoin kahden lausekkeen or-operaation tulos on aina true, jos ensimmäisen lausekkeen totuusarvo on true. Oikosulkuevaluoinnin käyttöä voidaan testata esimerkiksi siten, että toinen lauseke kaataa ohjelman, jos se evaluoidaan. Harjoituksen yhteyteen linkitetty esimerkkiohjelma (H4_T3_oikosulku.c), jossa on tällaiset and-ja or-lausekkeet. Ohjelman suorittaminen osoittaa, että kummassakin tapauksessa tehdään oikosulkuevaluointi. Sen sijaan aritmeettisten lausekkeiden evaluoinnissa ei yleensä käytetä oikosulkuevaluointia. Tehtävä 4. FORTRAN -kieli noudattaa aliohjelman parametrien välityksessä inout - semantiikkaa. Tämä voidaan kuitenkin toteuttaa kahdella tavalla: viitevälityksellä tai arvo-tulos -välityksellä. Selvitä Internetin avulla, miten FORTRANissa laaditaan parametreja käyttävä aliohjelma. Kirjoita tämän jälkeen ohjelma, joka selvittää kumpaa välitysmekanismia käyttämäsi FORTRAN-versio soveltaa. Ainakin osoitteessa http://www.tutorialspoint.com/codingground.htm on verkossa toimiva FORTRANkääntäjä. Ohje: Välitä aliohjelmalle sama muuttuja kahdessa eri parametrissa ja tutki parametrien arvon muuttumista aliohjelman sisällä. Jos intoa vielä riittää, selvitä sama asia Ada-kielen inout-parametreille. Alla on yksinkertainen Ada-ohjelma, jossa välitetään aliohjelmalle kokonaislukumuuttuja inoutparametrina. with Ada.Text_IO, Ada.Integer_Text_IO; use Ada.Text_IO, Ada.Integer_Text_IO; procedure Parameters is muuttuja: Integer; procedure ParTest(par: in out Integer) is par := 99; end ParTest; Put_Line("Testataan parametreja. Ennen:"); muuttuja := 11; Put(muuttuja,4); ParTest(muuttuja); New_Line; Put_Line("Jalkeen:"); Put(muuttuja,4); end Parameters;
Adassa ei voi antaa samaa muuttujaa kahdelle eri inout-parametrille, joten asiaa pitää testata muuten. Huomaa, että aliohjelman voi keskeyttää heittämällä poikkeus. Adassa poikkeuksen voi aiheuttaa raise-lauseella, esimerkiksi raise Program_Error; Poikkeuksen voi käsitellä kootussa lauseessa lisäämällä sen loppuun exception-osan -- Koodia jossa voi tulla poikkeus exception when Program_Error => -- poikkeuksen käsittelyä end; Vastaus. Harjoituksen yhteyteen linkitetyssä tiedostossa H4_T4_partest.for välitetään kahta parametria käyttävälle aliohjelmalle kutsussa sama muuttuja. Aliohjelmassa muutetaan toisen parametrin arvoa ja tulostetaan kummankin parametrin arvot. Verkon kääntäjällä tuotetussa ohjelmassa molempien parametrien arvo muuttui. Näin ollen kumpikin parametri viittaa samaan muuttujaan ja voidaan päätellä, että käytössä on viitevälitys. Arvo-tulosvälityksessä parametrit ovat kopioita, jolloin aliohjelman sisällä parametrin arvon muuttaminen ei vaikuttaisi toiseen parametriin. Tiedostossa H4_T4_partest.ada on Ada-kielinen ohjelma, jossa välitetään aliohjelmalle parametri in out-moodissa. Parametrimuuttujan alkuarvo on 11; muuttujaan sijoitetaan aliohjelmassa arvo 99, minkä jälkeen aiheutetaan poikkeus. Pääohjelman poikkeuskäsittelijässä huomattiin testattaessa, että parametrimuuttujan arvo säilyi arvossa 11. Tämä viittaisi siihen, että Ada käyttää arvo-tulos-välitystä, koska sijoitus ei vaikuttanut muuttujaan, kun aliohjelmasta poistuttiin epänormaalisti. Ellei poikkeusta aiheuteta, muuttujan arvo luonnollisesti muuttuu. Tehtävä 5. Tarkastellaan aliohjelmaa aliohjelman parametrina. Kirjoita C- (tai C++-) kielellä funktio laske_summa, joka saa parametrinaan reaalilukutaulukon, sen alkioiden lukumäärän ja prototyyppiä double val_fun(double) olevan funktion. Funktio laske_summa palauttaa summan parametrina saamansa funktion arvoista sovellettuna taulukon alkioihin. Sovella funktiotasi laskemaan taulukon double taulu[] = 1.0,2.0,3.0 neliöiden summa (= 1.0 2 + 2.0 2 + 3.0 2 = 1.0 + 4.0 + 9.0 = 14.0), ts. parametrina annetaan funktio double square(double x) return x*x;
Vastaus. Harjoituksen yhteyteen linkitettyyn tiedostoon H4_T5_CallBackSumma.c on toteutettu C-kielellä vaadittu takaisinkutsuohjelma. Ohjelmassa lasketaan myös taulukon alkioiden kuutioiden summa käyttämällä funktion square asemasta funktiota double cube(double x) return x*x*x;