Ohjelmointi 1, syksy 2007 -- Demo 9

Tehtävät julkaistaan:
 Tiistain luennolla 6.11.2007
Palautus viimeistään:
 13.11.2007 klo 18
100% tehtävistä tarkoittaa:
 6 kpl tehty

Tässä demossa on vastaavia kysymyksiä kuin kurssin tentissä. Nyt näiden muotoiluun ehditään vielä puuttumaan, jos herää kysymyksiä siitä, mitä kysymykset tarkoittavat tai mistä niihin valmentavaa tietoa löytyisi!

Contents

Tentti-preview

Tässä demossa on tulevat tenttikysymyksenne, por favor. Joka kerta tulee erilaiset koodilistaukset kaikkiin kohtiin, erilainen syntaksitehtävä, erilaiset luvut muunnettavaksi lukujärjestelmästä toiseen ja erilaiset ominaisuudet toteutettavaksi siihen erilaiseen ohjelmaan. Tavoite olisi, että vaikeustaso on kaikilla tenttikerroilla suurin piirtein sama. Vaikea tosin tietää tehtävän vaikeudesta mitään ennen kuin näkee, mitä porukka niihin osaa vastata...

Tuolla voi kurkistaa, miltä tenttipaperi näyttää sitten koetilanteessa paperille tulostettuna:

http://www.cc.jyu.fi/~nieminen/ohj1/tentti_hahmotelma.pdf

Tehtävä 1: Ohjelmakoodin ja suorituksen ymmärtäminen

Tutki seuraavaa ohjelmaa. Oleta, että se on olemassa tietokoneella siten että se voidaan kääntää ja suorittaa Java-työkaluilla:

/*  1*/  public class Tenttiohjelma2{                          // Ajanpuutteen vuoksi
/*  2*/      public static int teeLukuJonosta(String luku){    // liian samanlainen kuin
/*  3*/          return Integer.parseInt(luku);                // aiempi demo! Oikeasti
/*  4*/      }                                                 // voi olla mitä tahansa
/*  5*/                                                        // vastaavan tasoista!
/*  6*/      public static void main(String[] args){           /////////////////////////
/*  7*/          int lukum = 4;
/*  8*/          int i=0;
/*  9*/          int[] taulu = {-1,-2,-3,-4};
/* 10*/          StringBuilder sb = new StringBuilder("");
/* 11*/
/* 12*/          for (i = 0; i<lukum; i++){
/* 13*/              if (i == lukum / 2){
/* 14*/                  break;
/* 15*/              } else {
/* 16*/                  taulu[i] = teeLukuJonosta("12");
/* 17*/              }
/* 18*/              sb.append(taulu[i]);
/* 19*/          }
/* 20*/          String tuloste = sb.toString();
/* 21*/          System.out.println(tuloste);
/* 22*/      }
/* 23*/  }

Vastattavat kohdat (10 kpl) ja painoarvot pisteytyksessä (yht. 6p):

  1. Mikä on tiedoston nimi, johon lähdekoodi on tallennettu? (0.3p)
  2. Mikä on ajettavan tavukooditiedoston nimi? (0.3p)
  3. Millä komentorivikomennoilla käännät ja suoritat ohjelman? (0.4p)
  4. Missä järjestyksessä rivit 3, 7, 8, 9, 10, 13, 14, 16, 18, 20 ja 21 suoritetaan. Eli kirjoita em. rivinumerot siinä järjestyksessä kuin virtuaalikone suorittaa rivit (monta numeroa, osa mahdollisesti useita kertoja!) (2p)
  5. Mitä ohjelma tulostaa? (0.5p)
  6. Mitkä erilaiset tyyppimäärittelyt löydät ohjelmasta, kun viitteet eri luokkien olioihin tulkitaan eri tyypeiksi? Luettele siis kaikki tyypit, joita ohjelmassa käytetään. (0.5p)
  7. Mitkä muuttujat ovat olemassa, kun rivi 21 suoritetaan? Luettele muuttujien nimet. (0.5p)
  8. Mitkä ovat olemassaolevien primitiivimuuttujien arvot ohjelman lopussa? (0.5p)
  9. Moneenko eri olioon olisi saatavilla viite, jos rivin 21 jälkeen pitäisi lisätä koodirivi, joka käyttäisi jotakin aiemmin syntynyttä oliota? (0.5p)
  10. Ajattele tilannetta, jossa riviä 21 suoritetaan. Montako 8-bittistä tavua muistia tässä ohjelmassa määritellyt muuttujat vaativat sillä hetkellä yhteensä? Jätä huomioimatta olioiden kekomuistista käyttämä tila, mutta ota huomioon paikallisten viitemuuttujien viemä tila. (Javan tilavaatimukset oletuksineen luetellaan liitteessä) (0.5p)

Liite:

.
              Tyyppi       koko    literaaliesim.
                           (bit)
Totuusarvot   boolean      ? *     true, false
Merkit        char         16      'A', '\u0041'
Kokonaisluvut byte         8       14, 123, -128, 0x72
              short        16      -14, 0123, 32767
              int          32      14, -1234, 32767
              long         64      14L, 9223372036854775807
Liukuluvut    float        32      14.0, 1.234, 3.4e38
              double       64      14.0, 1.234, 4.9e-324
Olioviitteet  LuokanNimi   32 **

Huomautukset:

* Riippuu toteutuksesta

** Riippuu toteutuksesta; tentissä oleta kooksi neljä tavua.

Tehtävä 2: Pikkukysymyksiä ja käytännön taitoja

Kahdessa ensimmäisessä kohdassa tarkastele seuraavaa ohjelmakoodin pätkää:

/*  1*/      /* --------- Question: Variables and assignments -------- */
/*  2*/      int a = 4;
/*  3*/      int b = 6;
/*  4*/      int c = 10;
/*  5*/      int d;
/*  6*/
/*  7*/      System.out.println(d = a * (b + a) / c);
/*  8*/
/*  9*/      /* --------- Question: Objects and references --------- */
/* 10*/      String nul = "null";
/* 11*/      String hup = nul;
/* 12*/      StringBuilder sb = new StringBuilder(nul);
/* 13*/      sb.append(hup);
/* 14*/      String[] t = {hup, sb.toString()};
/* 15*/      hup = null;

Kuusi kohtaa, yht. 6p:

  1. Jäsennä rivi 7 kokonaan: Missä järjestyksessä kone suorittaa yksittäiset operaatiot? Taulukoi joka suorituksesta: operaattori, vasemman operandin lukuarvo, oikean operandin lukuarvo ja operaatiosta syntyvän tuloksen lukuarvo? (1.5 p)

  2. Piirrä graafisesti ohjelmanpätkän suorituksesta syntyvät paikalliset viitemuuttujat, oliot sekä kaikki viitteet paikallisista muuttujista olioihin tai olioista toisiinsa. Kuvassasi olio on laatikko, johon on kirjoitettu sen luokka ja sen verran sisältöä, että oliot tunnistaa kuvassa toisistaan. Viite on nuoli viittaajasta viitteen kohteeseen. (1 p)

  3. Kirjoita Java-kielen heksadesimaaliliteraalina bittijono 010011100101. (0.5p)

  4. Kirjoita Java-kielen oktaaliliteraalina bittijono 010011100101. (0.5p)

  5. Kirjoita Java-kielen 10-järjestelmän kokonaislukuliteraalina heksaluku 2a9. (0.5p)

  6. Määrittele syntaksi eli kielioppi, jonka mukaisesti voi kirjoittaa useita rivejä, joista jokaisella on pilkulla erotettuja kokonaislukuja vähintään yksi. Mitään muita merkkijonoja syntaksisi ei saa sallia. Johda yksittäisen merkin tarkkuuteen saakka. Merkkaa rivinvaihtoa symbolilla "n". Sallittu esim:

    4,-7,100
    2
    -19
    129814719,0
    
(2p)

Tehtävä 3: Koodin selkeys ja toimivuus

Kysymyksissä 3 ja 4 tarkastele seuraavaa ohjelmakoodia:

http://www.cc.jyu.fi/~nieminen/ohj1/demot/HuonoOhjelma2.java

(Aika pitkä laitettavaksi printattuun demoon niin laitoin vain linkin..) Katso myös miltä se näyttää tenttipaperissa:

http://www.cc.jyu.fi/~nieminen/ohj1/tentti_hahmotelma.pdf

Vastauksen muoto kysymyksiin 3 ja 4 (tentissä):

Tentti-istunnossa on viisi tärkeätä sääntöä, joiden noudattamatta jättäminen vie vastaavan vastauskohdan pisteet selkeästi nollaksi:

Kysymyksen 3 kaksi kohtaa:

  1. Korjaa koodi hyvien koodauskäytänteiden mukaisiksi. Muista perustella muutokset. Koodilistauksessa on seuraavat tahalliset virheet, jotka tulee korjata:
    • tyhjämerkkien käyttö lähdekoodissa ei täysin vastaa ohjelman rakennetta
  2. Ohjelman toiminnassa on selkeitä vikoja, jotka löytyvät, kun tutkii tarkkaavaisesti. Korjaa toiminnallisuuden viat. Muista perustella. Koodilistauksessa on seuraavat tahalliset virheet:
    • kolme syytä, joiden takia ohjelma ei käänny
    • kaksi kohtaa, joiden takia ohjelma kaatuu varmasti
    • yksi syy, jonka takia ohjelma ei toimi niinkuin se väittää toimivansa

Tehtävä 4: Ohjelmakoodin tuottaminen

Kysymys 4 arvostellaan riippumattomasti, mutta tässä käsitellään samaa ohjelmakoodia ja käytetään samaa muotoa vastaukselle kuin kysymyksessä 3. On tärkeätä, että käytät alkuperäisen (rikkinäisen) koodin rivinumeroita muutoskohtien ilmoittamiseen, koska tämän vastauksen tarkastaa eri henkilö eikä hän tiedä edellisessä kohdassa tehtyjä muutoksia!

Riippumatta siitä, osaatko vastata kysymykseen 3, oletetaan että ohjelmaan on nyt tehty tarvittavat korjaukset ja että se lähtökohtaisesti toimii niinkuin se lupaa käyttäjälle.

DEMOSSA 9 täytyy osata Eclipsen avulla vastata kysymykseen 3 noin kahdessa minuutissa... tentissä nyt vaan ei ole sitä luksusta, että IDE laittaa huutomerkin ongelmallisen kohdan vierelle. Se pitää pystyä löytämään lukemalla koodia itse.

Laajenna nyt ohjelmaa seuraavilla uusilla ominaisuuksilla:

  1. Ohjelman valikossa on toiminto, jota ei ole vielä toteutettu: Toteuta siis ensinnäkin loppuun taulukon arvojen kertominen käyttäjältä kysytyllä luvulla. Täydet pisteet toimivasta ratkaisusta, johon sisältyy uuden aliohjelman lisäys. (1.5p)
  2. Muuta toiminnallisuus sellaiseksi, että ohjelman suoritus jatkuu aina uudella toiminnolla niin kauan kunnes käyttäjä haluaa lopettaa. Tulkoon tästä lisävalinta samaan dialogiin, jossa kysytään suoritettavaa toimenpidettä. Analysoitavan lukutaulukon arvoja ei kuitenkaan tule arpoa satunnaisesti uudelleen joka kierroksella. (1.5p)
  3. Toteuta uusi ominaisuus: Taulukon arvojen tulostaminen rivitettynä. Tulkoon tästä uusi ominaisuus "Tulosta arvot" ohjelman päävalikkoon. Toiminto kysyy käyttäjältä alkioiden määrän, joka tulostetaan aina yhdelle riville; tätä varten on olemassa aliohjelma Apukirjasto.lueInteger(String ohjeteksti). Sitten pitää tulostua taulukon arvot siten että rivi katkaistaan aina halutun alkiomäärän jälkeen. Tulostuksen tulee toimia vaikka taulukon koko olisi erilainen jokaisella tulostuskerralla. Sijoita toiminto aliohjelmaan. (3p)

Moniulotteiset taulukot

Tehtävä 5: Matriisi

Viime kerran tehtävässä 4 tehtiin aliohjelma, joka luo kaksiulotteisen liukulukutaulukon, jossa on satunnaisia alkioita. Tällä tavoin tietokoneessa usein kuvataan matriisi, eli matemaattinen väline mm. lineaarikuvausten laskemiseen.

Level 1: Toteuta minkä tahansa kokoisen matriisin suurimman alkion etsiminen. Tietenkin aliohjelma palauttaa lukuarvon eikä tulosta itse mitään! Tässä pitää käydä läpi matriisin kaikki alkiot. Voit olettaa saavasi sarakkeiden määrän koodilla matriisi[0].length. Alkioiden indeksointi sitten ihan normaalisti matrisii[i][j].

(Javan taulukkototeutuksesta johtuen periaatteessa taulukon rivit eli matriisi[0], matriisi[1], jne voisivat viitata eri mittaisiin taulukoihin, jos ne olisi sillä tavoin luotu... matemaattisesti tällainen tietorakenne ei kuitenkaan olisi ainakaan tavallinen matriisi, joten jätä outo mahdollisuus toistaiseksi huomioimatta.)

Level 2: Jos Level 1 oli helppo, toteuta mielivaltaisen kokoisten matriisien kertolasku. Matemaattinen formulointi löytyy mistä tahansa lineaarialgebran kirjallisuudesta tai Googlettamalla "matrix multiplication". Aliohjelma palauttaa uuden matriisin, joka on parametrien matriisitulo, tai heittää poikkeuksen IllegalArgumentException, jos syötematriisien dimensiot eivät sovellu kertolaskun määritelmään.

Dynaamiset tietorakenteet

Tehtävä 6: ArrayList

ArrayList käy tämän kurssin esimerkiksi Javan valmiista tietorakenteista. Ne ovat käteviä, jahka hahmottaa, miten käyttäminen tapahtuu. Pieni määrä uutta syntaksia tässä tulee. Alla on lähes valmiiksi pureskellut esimerkit, jotka antavat niihin pienen selviytymispaketin... Lisää löytyy oppikirjasta. Ns. geneerinen ohjelmointi, tyyppiparametrit ja omien vastaavien luokkien tekeminen on kakkoskurssin asiaa. Ykkösen jälkeen pitäisi olla "valmius yksinkertaisten Java-ohjelmien tekemiseen". Esim. ArrayListin käyttötaito dokumentaation ja esimerkkien avulla on ehdottomasti välttämätöntä tuollaisen "valmiuden" syntymiselle. Niinpä tämä on varsinaisena demotehtävänä.

Tee ohjelma, joka toimii konsolissa seuraavasti (kysyy aina käyttäjältä, ja antaa tulosteen):

Montako merkkijonoa haluat lajitella>4
Syötä 1. jono>siirappi
Syötä 2. jono>laventeli
Syötä 3. jono>manteli
Syötä 4. jono>basilika

Jonot ovat aakkosjärjestyksessä:
basilika
laventeli
manteli
siirappi

Vinkiksi vähän koodia kommentteineen:

import java.util.ArrayList;
import java.util.Collections;

...

ArrayList<String> lista = new ArrayList<String>();

// tekee ArrayList-luokan olion, johon voi tallentaa kätevästi
// viitteitä String-olioihin. Kulmasulkusyntaksi on uusi; sen merkitys
// on tarkentaa mm. ArrayListi-tyyppiä sillä tavoin, että siihen ei
// voi laittaa muita kuin String-viitteitä; ei sen kummempaa sinänsä.

lista.add("siirappi");
// lisää listaan yhden alkion (siis listan viimeiseksi menee
// vakiomerkkijonon viite).

...

Collections.sort(lista);
// Lajittelee listan. Siis listaolio muuttuu siten että kun se jatkossa
// käydään alkioittain läpi, alkioiden keskinäinen järjestys vastaa
// "luonnollista järjestystä", esim. merkkijono-olioilla aakkosjärjestystä.

for (String s: lista) doSomethingWith(lista);
// Uudessa Javassa on tällainen kätevä for-päivityksen ilmaisutapa: Silmukka
// käy läpi listan alkiot ja joka kierroksella viite ``s`` viittaa aina
// käsiteltävään alkioon.

// Em. on suositeltavaa jä näppärää. Mutta jos se on liian ufoa,
// niin toki käy myös seuraava, joka näyttää enemmän samalta kuin
// tähän asti nähty kokonaislukuja laskeva for-silmukka:
for (int i=0; i<lista.size(); i++) doSomethingWith(lista.get(i));

Bonussektori

Tehtävä 7: Oma tenttikysymys

Keksi perusohjelmointitaitoa mittaava tenttikysymys:

  • kirjoita tehtävänanto
  • kirjoita pisteytysohje: kuinka suuri painoarvo 24 tenttipisteestä kysymyksellä mielestäsi on, ja miten tulee arvioida osapisteet, jos vastaus ei ole täydellisesti oikein
  • kerro, minkä osa-alueen taitoja kysymyksesi mittaa ja miksi se on merkittävä kysymys
  • arvioi kauanko vastauksen tarkastamiseen menee pahimmillaan ja keskimäärin yhtä tenttipistettä kohden (esim. Ohjelmointi 1:n ensimmäisessä tentissä opettajat tarkastavat yhteensä 3000 tenttipisteen edestä vastauksia, mihin saa neljältä henkilöltä kulua muun työn ohella korkeintaan 14 päivää kalenteriaikaa).
  • tässä demossa nähdyn esitentin kysymystyypit eivät käy

HUOM: vastaamalla joudut seuraavaan tilanteeseen:

  • saatat saada vastata omaan kysymykseesi tentissä :-)
  • luovutat oikeuden käyttää kysymystä tenttikysymyksenä tai demotehtävänä tulevilla kurssikerroilla
  • toivottavasti ennakoivasti hieman vaimenet urputuksesta tentin arvosteluperiaatteiden suhteen; ei ole ainakaan minun mielestä maailman helpoin homma miettiä noita kohdilleen ...