wiki:s2012/tentti1
Last modified 3 years ago Last modified on 2014-09-07 17:42:08

Ohjelmointi 1, tentti 12.12.12

ITKP102 Ohjelmointi 1 – Tentti 12.12.2012

Vastaa neljään tehtävään jotka valitset tehtävistä 1–6 (yhteensä enintään 24 (+ 2) pistettä) HUOM! Jokaisen tehtävän vastaus omalle paperilleen. Paperit palautetaan eri pinoihin!

Jos vastauksessa tarvitset jotakin funktiota API-kirjastosta (C#:n kirjasto) ja et muista tarkkaan mikä oli funktion/metodin nimi, niin kirjoita funktion esittely (parametreineen) ja kommentti siitä mitä sen pitäisi tehdä. Et saa itse keksiä funktioita, joita ei ole olemassa (ellet itse myös toteuta niitä).

Merkkijonon paloitteluun voi käyttää mm. Split-metodia tai metodien IndexOf? ja Substring kombinaatiota. Merkkijonosta saa kokonaisluvun Parse-metodin avulla ja kokonaisluvusta merkkijonon ToString?-metodin avulla. Esimerkiksi seuraavasti:

string k1 = "12", jono = "ab, cd";

int luku = int.Parse(k1);        // nyt: luku == 12      
string k2 = luku.ToString();     // nyt: k2 == "12"  

char[] erottimet = {',', ' '};
string[] osat = jono.Split(erottimet,StringSplitOptions.RemoveEmptyEntries);
                                 // osat[0]=="ab"
                                 // osat[1]=="cd"

1. Merkkijonojen käsittelyä

Olette erikoislaatuisessa tilanteessa kun tentti alkaa klo 12:12, niin päivämäärä ja kellonaika on silloin 12.12.12 12:12. Tällainen yhdistelmä ei enää toistu elinaikananne. Tee aliohjelma, joka palauttaa onko annettu päivämäärä ja kellonaika (esim “12.12.2012 12:12”) joka on annettu muodossa pp.kk.vvvv hh:mm sellainen, että kukin luku on sama (eli esim 12.12.12 12:12 kun vuodesta jätetään sadat ja tuhannet pois).

Alla esimerkkitestit aliohjelmalle. Vastaukseesi ei tarvitse tässä tapauksessa toistaa testejä! Aliohjelman muu kommenttiosa on kuitenkin kirjoitettava samoin kuin aliohjelman toteutus. Kirjoita myös yksi esimerkki, miten aliohjelmaa kutsuttaisiin pääohjelmasta (tällä kannattaa jopa aloittaa).

/// <example>
/// <pre name="test">
/// OnkoLuvutSamatPvm("12.12.2012 12:12") === true;
///  OnkoLuvutSamatPvm("09.09.2009 09:09") === true;
///  OnkoLuvutSamatPvm("") === false;
///  OnkoLuvutSamatPvm(null) === false;
///  OnkoLuvutSamatPvm("xx.xx.yzxx xx:xx") === true;
///  OnkoLuvutSamatPvm("24.12.2012 12:24") === false;
///  OnkoLuvutSamatPvm("00.00.0000 00:00") === true;
///  OnkoLuvutSamatPvm("88.88.2088 88:88") === true;
///  OnkoLuvutSamatPvm("07.07.2007") === false;
/// </pre>
/// </example>

BONUS (+2p): Ota huomioon myös testitapaukset kuten "9.9.2009 9:09" -> true ja "1.1.2001 1:01" -> true. Lisää ComTest?-testit ja muuta koodi niin että selviää tästä. xx-kohdan testin saat muuttaa halutessasi falseksi jos se tuottaa toteutukseen vähemmän if-lauseita.

2. Muuttujat ja aliohjelmat

Vastaa kysymyksiin a–h.

Muuttujat

Mitä seuraavissa tapauksissa tulostuu?

1    int a = 5;
2    int b = a;
3    Console.WriteLine(b);  // a) Mitä tulostuu?     (1p)
4    a = 6;
5    Console.WriteLine(b);  // b) Mitä nyt tulostuu? (1p)

Ovatko seuraavat muuttujat C#-kielen mukaisia? Ovatko tyypit, nimet ja asetetut arvot mahdollisia ja ohjelmoijan kannalta järkeviä? Perustele muutamalla sanalla mahdolliset korjausehdotuksesi.

c)    int kissojenMaara = 5.0;                  // (0.25p)
d)    string etunimi = "Jouni";                 // (0.25p)
e)    double kerroin = 1.2;                     // (0.25p)
f)    string välimatkakilometreinä = "200";     // (0.25p)

Aliohjelmat

g) Anna esimerkit kahdesta erilaisesta tavasta (erilainen parametrien määrä) kutsua seuraavaa aliohjelmaa, jonka esittelyrivi (header row) on:   (1p)

public int MontakoEsiintymaa(string[] sanat, string haettava,
                            bool kirjainkokoEiVaikuta = true)

h) Kirjoita seuraavasta pääohjelmasta kutsuttaville aliohjelmille EtsiPienin ja MuunnaTekstiksi esittelyrivit (header row). Algoritmisia toteutuksia ei tarvitse tehdä, vaan pelkät esittelyrivi kummastakin riittävät. (2p)

1   public static void Main(string[] args)
2   {
3       int[] luvut = {3, 5, 1, 2};
4       int pienin = EtsiPienin(luvut);
5       System.WriteLine(pienin); // tulostaa 1
6       string luvutTekstina = MuunnaTekstiksi(luvut, " - ");
7       System.WriteLine(luvutTekstina); // tulostaa 3 - 5 - 1 - 2
8   }

3. Taulukko

Tutki seuraavaa koodinpätkää ja vastaa sen pohjalta kysymyksiin.

Mitä ohjelma tulostaa? Täydennä aliohjelma MuutaPieneksi niin että se toimii kommenttien mukaisesti. Pääohjelmassa on esitetty kysymyksiä riveillä 11 ja 16. Vastaa kysymyksiin, kun ohjelman suorittamisessa ollaan menossa kyseisellä rivillä.

1    public static void Main(string[] args)
2    {

3        String[] elukat = {"Lehmä", "Kissa", "Koira", "Kana", "Hevonen" };
4        String[] sanoja = {"ystävät", "ystäviä"};
5
6        Console.WriteLine(elukat[1] + " ja " + elukat[3] + " ovat "
7            + elukat[2] + "n " + sanoja[1]);
8
9        MuutaPieneksi(elukat);
10
11       // C1. Mitä on taulukossa elukat?
        // Kirjoita tenttipaperille alekkain kaikki taulukon alkiot.
12
13        String[] tmp = sanoja;
14        tmp[1] = "";
15
16        // C2. Mitä taulukko tmp sisältää? Entä sanoja? Miksi?
17    }
18
19    /// <summary>
20    /// Aliohjelma, joka muuttaa sille parametrina viedyn
21    /// taulukon jokaisen alkion pieniksi kirjaimiksi.
22    /// </summary>
23    /// <param name="taulukko">Käsiteltävä taulukko</param>
24    /// <example>
25    /// <pre name="test">
26    /// String[] taul = {"EKA", "toKa", "kolmas"};
27    /// Taulukointi.MuutaPieneksi(taul);
28    /// String.Join(", ", taul) === "eka, toka, kolmas";
29    /// String[] taul2 = {""};
30    /// Taulukointi.MuutaPieneksi(taul2);
31    /// String.Join(", ", taul2) === "";
32    /// </pre>
33    /// </example>
34    public static void MuutaPieneksi(String[] taulukko)
35    {
36        // B. TÄYDENNÄ
37    }

4. Toiston poisto

Poista alla olevasta koodista toisto arpomalla listan alkiot silmukassa ja tekemällä aliohjelma TulostaMontakoValilla, joka tulostaa, montako lukua annetussa listassa on annetulla välillä. Kutsu sitten tätä aliohjelmaa pääohjelmasta sopivilla parametreilla.

public static void Main(string[] args)
{
       List<int> luvut = new List<int>();
       Random r = new Random();

       luvut.Add(r.Next(10));
       luvut.Add(r.Next(10));
       luvut.Add(r.Next(10));
       luvut.Add(r.Next(10));
       luvut.Add(r.Next(10));
       luvut.Add(r.Next(10));

       int maara = 0;
       for (int i = 0; i < luvut.Count; i++)
       {
           if ( 0 <= luvut[i] && luvut[i] <= 5)
               maara++;
       }

       Console.WriteLine("Listan luvuista {0} kpl on välillä [0,5]", maara);
   
    maara = 0;
       for (int i = 0; i < luvut.Count; i++)
       {
           if ( 6 <= luvut[i] && luvut[i] <= 9)
               maara++;
       }

       Console.WriteLine("Listan luvuista {0} kpl on välillä [6,9]", maara);
}

5. Teoriaa

Alla on kuusi kohtaa joista jokaisesta saa yhden pisteen. Vastaa kohtiin lyhyesti enintään muutamalla virkkeellä.

  • Mitä tarkoittaa aliohjelman kuormittaminen (function overloading)?
  • Mitä tarkoittaa, että olio "muuttuu roskaksi"?
  • Esittele vähintään kolme loogista operaattoria ja kerro mitä kukin tekee.
  • Kuinka paljon on C#:ssa 25/4? Entä 25%4?
  • Mikä ero on String ja StringBuilder? -luokilla?
  • Mikä ero on for ja foreach -silmukoilla?

6. Olioviitteet

Vastaa seuraavaan neljään kysymykseen, jotka ovat kommentteina ohjelmassa

public static void Main(string[] args)
{
   StringBuilder kissa = new StringBuilder("kissa");
   StringBuilder koira = new StringBuilder("kissa");
   if (kissa == koira) Console.WriteLine("gfffögkfhjd");
   // 1. Tulostuuko edellinen rivi? Perustele. (1p)
   kissa = koira;
   koira = new StringBuilder("koira");    
   // 2. Mihin olioviitemuuttujat kissa ja koira viittaavat
   //    tällä hetkellä? (2p)
   lisaaHaukkuu(koira.ToString());
   lisaaHaukkuu(kissa);
   Console.WriteLine(kissa + " ja " + koira);           
   // 3. Mitä edellä oleva rivi puolestaan tulostaa?
   //    Perustele. (1p)
}


/// <summary>
/// Lisää annetun merkkijonon perään " haukkuu"
/// </summary>
/// <param name="elain">Merkkijono, jonka perään lisätään</param>
/// <returns>Muutettu merkkijono</returns>
public static string lisaaHaukkuu(string elain)
{
   elain = elain + " haukkuu";
   return elain;
}


// 4. Mitä seuraavassa aliohjelmassa on vikana?
//    Miten korjaisit sen? (2p)
/// <summary>
/// Lisää annettun StringBuilderin sisällön perään " haukkuu";
/// </summary>
/// <param name="elain">StringBuilder, jonka perään lisätään</param>
public static void lisaaHaukkuu(StringBuilder elain)             
{
   elain = new StringBuilder(elain.ToString() + " haukkuu");
}

Mallivastaukset, arvosteluperusteet ja kommentteja

1. Merkkijonojen käsittelyä

public static bool OnkoLuvutSamatPvm(String pvm)
{
   if (pvm == null || pvm.Length < 8) return false;

   String[] luvut = pvm.Split(new char[]{'.', ' ', ':'});
   if (luvut.Length != 5) return false;

   String apu = luvut[0];
   for (int i = 1; i<luvut.Length; i++)
   {   
       String luku = luvut[i];

       int pit1 = apu.Length;
       int pit2 = luku.Length;

       //Verrataan kummankin kahta viimeistä kirjainta
       if (pit1 < 2 || pit2 < 2 || apu[pit1-1] != luku[pit2-1] || apu[pit1-2] != luku[pit2-2]) return false; 
       
       apu = luku;
   }
   
   return true;
}

Arvosteluperusteet:

Arvostelussa lähdin arvioimaan yleisesti ohjelman toimivuutta ja miinustamaan täysistä pisteistä, jos ohjelmassa esiintyi virheitä. Ohjelmien toteutuksia oli monenlaisia ja en lähtenyt miinustamaan pisteitä tietynlaisista ratkaisuista tai antamaan niistä suoraan lisäpisteitä. Kuitenkin hyvät rakenteet ja helppolukuisuus saattoivat muuttaa arvosanaa parempaan suuntaan täpärissä tilanteissa ja huonot rakenteet huonompaan suuntaan.

Tärkeintä oli lähinnä, että ohjelma toimi ja siinä oli oikea ajatus. Yksittäisistä syntaksivirheistä tai hieman väärin käytetyistä metodikutsuista en suoraan miinustanut pisteitä, vaan se riippui tilanteesta. Testitapaukset toimivat pohjana ohjelman toiminnalle ja niistä selviämistä seurasin tarkkaan. Kuitenkin, jos esimerkiksi tietty virhe esti kaikkien testien onnistumisen miinustin pisteitä ainoastaan tästä tietystä virheestä enkä kaikista epäonnistuneista testeistä.

Tilanteissa, jossa selvästi tehtävää ei osattu ja virheiden määrä kasvoi niin suureksi, että pisteet saattoivat mennä nolliin, aloin etsiä ohjelmasta hyviä asioita. Näistä yksittäisistä kohdista saattoi saada pieniä hajapuolikkaita (esim. hyvä kommentointi).

Yleisimpiä virheitä oli testitapausten huomiotta jättäminen. Esimerkiksi syötteen ollessa null, aliohjelma kaatoi suurimmassa osassa vastauksia ohjelman. Tämän lisäksi yleisiä olivat pituuden tarkistamatta jättäminen tai kirjainsyötteen huomioimatta jättäminen merkkijonoja parsittaessa.

Allaolevat miinustukset eivät ole aivan absoluuttisia, vaikka niitä seurasinkin suurimmalta osin. Toteutuksia oli monenlaisia ja nämä edustavat niitä virheitä, joita suurimmassa osassa toteutuksista saattoi esiintyä. Yleisesti yksittäisestä virheestä lähti puoli pistettä pois.

Yleisiä virheitä (-0.5p)

  • Jokin testi ei toimi tai testin syöttö kaataa ohjelman.
  • Kommentoinnin osa puuttuu (summary, param, returns).
  • Aliohjelmakutsun esimerkki puuttuu/puutteellinen.
  • Syntaksivirheitä paljon.
  • Esittelyrivi väärin.
  • Palautus väärin.
  • Eri arvojen vertailu väärin.
  • Bonustehtävään vastattaessa testien kirjoittamatta jättäminen.

Suurimmalta osin tehtävä meni hyvin ja bonuspisteiden kanssa tässä taisi olla kokeen pisterikkain tehtävä. Vastaajia oli harmittavan vähän siihen nähden, miten paljon tehtävästä oli mahdollista saada pisteitä. Erityisesti bonustehtävästä sai hyvin napattua 2 pistettä, jos vain otti nämä tapaukset huomioon ja muisti lisätä testit.

2. Muuttujat ja aliohjelmat

Muuttujat a) 5 (1p)

b) 5 (1p)

c) Oikeampi olisi: int kissojenMaara = 5; Esitetty arvo 5.0 ei olisi mahdollinen, koska se on tyypiltään double. Kissojen määrä on luonteeltaan kokonaisluku, joten tyypiksi int. (0.25p)

d) OK tällaisenaan (0.25p)

e) OK tällaisenaan (0.25p)

f) string ei ole järkevä tyyppi välimatkalle (muuten kuin ehkä tulostettaessa ruudulle). Tyypiksi mieluummin double tai mahdollisesti int. Ääkköset ovat sallittuja muuttujien nimissä, mutta niitä kannattaisi välttää. Parempi olisi: double valimatkaKilometreina = 200.0; Myös vastauksesta, jossa on todettu rivin olevan kielen mukaan mahdollinen, saa pisteet, kunhan on ollut selvää, että numeroita ei välttämättä kannata säilyttää stringissä. (0.25p)

Aliohjelmakutsut g) MontakoEsiintymaa(sanat, "sana"); (0.5p)

MontakoEsiintymaa(sanat, "sana", false); (0.5p)

h) public static int EtsiPienin(int[] luvut) (1p)

public static string MuunnaTekstiksi(int[] luvut, string erotin) (1p)

Tehtävän 2 arvosteluperusteista

Ylimääräisistä (eli sellaisista, joita tehtävänannossa ei pyydetty) virheellisistä koodiriveistä tai virheellisistä dokumentaatiokommenteista on vähennetty 0.25--0.5 pistettä riippuen virheiden suuruuksista.

public- tai static-sanan puuttumisesta on vähennetty 0.25 pistettä.

h-kohdassa 0.5 pistettä pois, jos toisen parametrin tyyppinä on char eikä string, kuten piti.

g- ja h-kohdissa pisteitä maksimissaan 0.25, jos parametrit ovat aivan mitä sattuu.

3. Taulukko

Vastauksia yhteensä: 156 Keskiarvo: 4.13

a) Kissa ja Kana ovat Koiran ystäviä

  • 0.5p per taulukon sana. Eli jos kaikki sanat Kissa, Kana, Koiran ja ystäviä oikein niin 2p

b)

   public static void MuutaPieneksi(String[] taulukko)
   {
       for (int i = 0; i < taulukko.Length; i++)
       {
           taulukko[i] = taulukko[i].ToLower();
       }
   }
  • Maksimi 2p.
  • Osapisteitä sai siitä, että osasi käydä taulukon läpi (0.5p) tai käyttään ToLower tai vastaavaa metodia oikein (0.5p).
  • Miinuspisteitä tuli -0.5p jos oli palauttanut taulukon vaikka kyseessä on void tyyppinen aliohjelma.
  • Monessa vastauksessa yritetty käyttää foreach silmukkaa, näistä toteutuksista sai yleensä korkeintaan yhden pisteen. Vrt. teht 5.

c)

Rivillä 11: (1p)
elukat[0]    "lehmä"   
elukat[1]    "kissa"   
elukat[2]    "koira"   
elukat[3]    "kana"   
elukat[4]    "hevonen"

Rivillä 16: (0.5p)
sanoja[0]  "ystävät"
sanoja[1]  ""
tmp[0]  "ystävät"
tmp[1]  ""

Perustelu (0.5p): tmp viittaa sanoja-taulukkoon, jolloin sijoitettaessa tmp-taulukkoon, tapahtuu sijoitus oikeasti sanoja-taulukkoon.

  • Elukat taulukko osattu pääosin hyvin, joskin useassa vastauksessa luultiin, että koska MuutaPieneksi ei palauta mitään niin elukat taulukko ei muuttuisi. Kuitenkin, koska taulukko on olio, voidaan sitä käsitellä aliohjelmasta suoraan.
  • tmp ja sanoja taulukoiden kanssa vaikeuksia, monesti luultiin, että taulukoiden alkioita kopioitiin taulukosta toiseen.

4. Toiston poisto

Arvosteluperusteet:

Silmukka oikein: 2p

  • Silmukan rajat oikein (joko while (luvut.Count < 6) tai for (int i = 0; i < 6; i++) tai for (int i = 1; i <= 6; i++)): 1p
  • Silmukan runko oikein: 1p

Aliohjelma oikein: 3p

  • Esittelyrivi oikein: 1p
  • Tulostuslause oikein: 1p
  • Muut osaset oikein: 1p

Aliohjelman kutsut oikein: 1p

Miinukset (verrattuna täyteen pistemäärään):

Silmukka:

  • Silmukan rajat väärin (arpoo liikaa/liian vähän lukuja): -1p
  • Silmukan rajat huonosti kuvaavia, joskin arpoo oikean määrän, esim: for (int i = 1; i < 7; i++): -0.5p
  • Silmukan runko väärin (esim. luvut[i].Add(r.Next(10)) tai Random-olio luodaan silmukan sisällä tai ylimääräinen "i++"): -1p

Aliohjelman esittelyrivi:

  • Aliohjelman static-avainsana puuttuu: -0.5p
  • Aliohjelman paluuarvon tyyppi väärin: -1p
  • Aliohjelma saa liian vähän parametreja: -1p
  • Aliohjelman parametreista puuttuu tyypit: -1p
  • Aliohjelman parametrien nimet eivät ole kuvaavia (esim. "x" ja "y"): -0.5p

Muita mahdollisia virheitä:

  • Puolipiste(itä) puuttuu: -0.5p
  • Aliohjelman loppusulku } puuttuu: -0.5p
  • Aliohjelman lokaalin muuttujan esittely puuttuu: -1p
  • Aliohjelman lokaalin muuttujan alustus puuttuu: -1p
  • Pääohjelmasta puuttuu runko (on ainoastaan for-silmukka ja kutsut): -1p

Joitakin erikoistapauksia:

  • Aliohjelma palauttaa lukumäärän pääohjelmaan, joka tulostaa sen: 1.5p aliohjelmasta
  • Aliohjelma tulostaa kaksi kertaa (eli on vain kopioitu pääohjelman rivit aliohjelmaan eikä osattu poistaa toistoa): 0p aliohjelmasta
  • Tehtävä sinällään oikein, mutta ohjelma ei toimi samalla tavalla kuin alkuperäinen (esim. lukujen määrä kysytään int.Parse(Console.ReadLine()) -kutsulla ja/tai aliohjelmakutsuun on keksitty omat luvut): 4p koko tehtävästä

Mallivastaus:

public static void Main(string[] args)
{
    List<int> luvut = new List<int>();
    Random r = new Random();
    for (int i = 0; i < 6; i++)
        luvut.Add(r.Next(10));
    TulostaMontakoValilla(luvut, 0, 5);
    TulostaMontakoValilla(luvut, 6, 9);
}

public static void TulostaMontakoValilla(List<int> luvut, int alaraja, int ylaraja)
{
    int maara = 0;
    for (int i = 0; i < luvut.Count; i++)
    {
        if ( alaraja <= luvut[i] && luvut[i] <= ylaraja)
            maara++;
    }
    Console.WriteLine("Listan luvuista {0} kpl on välillä [{1},{2}]",
                    maara, alaraja, ylaraja);
}

5. Teoriaa

Arvostelukriteerit:

1. Aliohjelman kuormittaminen

  • (1.0p)Samanlaisia aliohjelmaesittelyjä tehdään useampia, mutta eri parametrimäärällä. Esim. void PiirraPallo(Vector2D piste); ja

void PiirraPallo(double x, double y);

  • Kertomalla pelkästään parametrien oletusarvoista sai 0.50p.

Huonoiten osattu tehtävä. Kuormittaminen myöntämättä kuulostaa negatiiviselta asialta, vaikka on sitä päinvastoin. http://en.wikipedia.org/wiki/Function_overloading

Asia kuitenkin käytiin demoissa läpi (on myös oleellinen) ja osa porukasta tiesi tämän täydellisesti.

2. Olio roskaksi

  • (1.0p) Kun muistissa olevaan olioon ei viitata enää mistään (esimerkiksi muuttujasta), muuttuu olio "roskaksi" (jonka C#:n GarbageCollector? aikanaan siivoaa muistista pois)

Tämä osattu hyvin

3. Loogisia operaattoreita

Esimerkiksi == (yhtäsuuruus), != (erisuuruus), ! (jos epätosi, niin tosi), < (pienempi kuin), > (suurempi kuin).

  • (0.33p) Jokaisesta oikeasta operaattorista lyhyellä kuvauksella (näitä voi tarkistaa luentomonisteen Loogiset operaattorit -kappaleesta)

Osa sekoitti muita operaattoreita, kuten lisäys- ja vähennyslaskuja mukaan. Nyt kuitenkin haluttiin LOOGISIA operaattoreita.

4. Laskutoimitukset

  • (0.5p) 25/4 = 6 (desimaalit tippuvat pois jos kummatkin luvut ovat kokonaislukuja)
  • (0.5p) 25%4 = 1 (Jakojäännös, eli 25 - (4 * 6) = 1)

Tämä osattiin hyvin, muutama jätti desimaalit vastaukseen tai laski jakojäännöksen väärin vaikka ilmoitti sen olevan jakojäännöslasku!

5. String vs StringBuilder?

  • (0.5p) String muuttumaton, joten aina String-oliota muutettaessa varataankin muistista uusi paikka
  • (0.5p) StringBuilderin? sisältöä voidaan muuttaa luomatta uutta instanssia (-> nopeampaa ja rasittaa vähemmän suorituskykyä)

Tämä osattiin hyvin.

6. For vs foreach

Foreachilla käydään tietorakenteen jokainen alkio järjestyksessä läpi, mutta sillä ei esimerkiksi alkioiden indeksejä saada (suoraan/luotettavasti) selville, eikä foreachilla voi sijoittaa tietorakenteen paikkaan uutta alkiota.

  • (1.0p) Foreach käy alkiot alusta loppuun
  • Foreachilla ei tiedetä alkioiden indeksejä (ei ole indeksimuuttujaa jota kasvatetaan kuten for-silmukassa voi olla, eikä ole järkeä luoda erikseen sellaista)
  • Foreachilla ei voida sijoittaa alkion paikalle uutta alkiota.

Tässä haettiin muitakin tärkeitä foreachin ominaisuuksia kuin "menee alkiot alusta loppuun", mutta joko kysymys oli muotoiltu huonosti "Mikä ero on.." tai ei vain muistettu. Siksi arvostelin tämän löyhemmin.

6. Olioviitteet

Suluissa kertauksena tarkempi korjaus yleisimpiin virheisiin.

1. Tehtävä

  • Ei tulostu. ½p
  • kissa ja koira viittaavat eri olioihin/muistipaikkoihin ½ p

(Ei tulostu, vaikka kummassakin on sama sisältö. StringBuilderin ==-operaattorissa ei verrata sisältöä vaan olioita.)

2. Tehtävä

  • kissa viittaa entiseen (rivillä 3 esiteltyyn) koiraan, jonka sisältönä on "kissa". 1p
  • koira viittaa (rivillä 7 luotuun) uuteen olioon, jonka sisältönä on "koira". 1p
  • viittaa itseensä tai muuta hämärää, mutta sisältö on oikein. 0,5p

(kissa ei viittaa olioviitemuuttujaan koira, vaan sen sisältöön. Olio, johon kissa viittasi aikaisemmin muuttuu roskaksi, koska siihen ei enää viitata. )

3. Tehtävä

  • Tulostaa: "kissa ja koira" (0,5p)
  • kissa ei muutu, koska aliohjelmassa luodaan uusi olio sen sijaan, että muutettaisiin oliota, johon myös kissa-muuttuja viittaa. 0,25
  • koira ei muutu, koska sen sisältö viedään stringinä aliohjelmaan, eikä aliohjelman palauttamaa uutta merkkijonoa tallenneta mihinkään. 0,25p

4.Tehtävä

  • Aliohjelmassa tehdään uusi StringBuilder, vaikka tarkoituksena olisi muokata olemassa olevaa, koska mitään ei palauteta. 1 p
    • (Uusi jono siis sijoitetaan tilapäisesti lokaaliin parametriin ja se häviää kun aliohjelmasta poistutaan.)
    • Ei pidetä uuden olion syntymistä syynä toimimattomuudelle, mutta tajutaan kuitenkin uuden olion syntyminen ja halutaan poistaa se. 0,5 p
  • Aliohjelman sisällön pitäisi olla pelkästään elain.Append(" haukkuu"); (Insert toimii myöskin) 1p
    • Jos aliohjelmassa on tämän rivin lisäksi jotain muuta (esim return) ja ei luoda uutta StringBuilderia (Jolloin ohjelma siis toimisi käytännössä oikein) 0,5 p
    • (Aliohjelman ei ole tarkoitus palauttaa mitään, koska pääohjelmassa ei ole muuttujaa, johon palautettu muuttunut tieto tallennettaisiin. Pelkän returnin lisääminen ei siis saisi ohjelmaa kokonaisuudessaan toimimaan oikein. StringBuilderia ei tarvitse palauttaa, koska pääohjelmasta annetaan olioviite StringBuilder-olioon, jota muutetaan aliohjelmassa. Aliohjelman elain ja pääohjelman kissa ovat olioviitemuuttujia, jotka kumpikin viittaavat siis samaan olioon. Tällöin jos eläintä muokataan, muuttuu myös olio, johon kissa viittaa. Kun elain muutetaan viittaamaan uuteen StringBuilderiin,ei muuteta enää oliota, johon myöskin pääohjelman kissa viittaa.)
    • (elain = elain + " haukkuu" tuottaa virheen, sillä StringBuilderin perään ei voi lisätä stringiä. Tämä lause toimii, kun elain on string (jolloin yhdistetään kaksi stringiä ja luodaan niistä uusi olio), mutta ei silloin, kun se on StringBuilder. StringBuilderin ollessa kyseessä käytetään Appendia, kun halutaan lisätä loppuun jotain. Appendin nimeä ei tarvinnut muistaa, kunhan muisti, että jotain StringBuilderin omaa metodia piti käyttää tässä kohti.)
  • Aliohjelman nimen pitäisi olla standardien mukaan isolla. 0,25p (Maksimi pistemäärä tehtävästä oli kuitenkin 2 pistettä)

Yleisiä huomioita tehtävässä ilmenneistä ongelmista

Varsin yleinen virhe oli kuvitella, että sekä kissa että koira muuttujat viittaavat seuraavien rivien jälkeen StringBuilderiin, jonka sisältönä on "koira".

StringBuilder kissa = new StringBuilder("kissa");
StringBuilder koira = new StringBuilder("kissa");
kissa = koira;
koira = new StringBuilder("koira");

Jotain on siis jäänyt mieleen olioista, mutta ei olla sisäistetty, että kissa = koira laittaa kissan viittaamaan koira-muuttujan sisältöön (olioon, johon koira viittaa), eikä itse viitemuuttujaan koira. Tällöin kummastakin muuttujasta voidaan muuttaa samaa StringBuilder-oliota niin kauan, kuin ne viittaavat samaan olioon. Kun toinen laitetaan viittaamaan eri olioon, tämä ei muuta sitä, mihin toinen muuttuja viittaa.

Toinen hyvin yleinen ajattelutapa oli, että aliohjelman, mihin viedään StringBuilder parametrina, pitää myös palauttaa se. Vaikka edellisessä tehtävässä monet ajattelivat, että koiraa muuttamalla kissakin muuttuu, sitä ei oltu osattu soveltaa niin, että sama voisi olla mahdollista myös aliohjelman ja pääohjelman välillä. Tämä siitä huolimatta, että demoissa ja ohjaustehtävissä oli useampikin esimerkki StringBuilderia tai taulukkoa muokkaavasta aliohjelmasta, mistä ei palautettu mitään.