Tehtävä 4 c++ ja dynaamisuus

Malliratkaisut ja arvosteluperusteet. Tehtävän maksimipistemäärä oli 7 pistettä. Maksimin saavutti yksi opiskelija. Tehtävän keskiarvo oli 3.87 pistettä.

a) kuva tietorakenteesta (max 0.5 p)

Riittää piirtää tehtävän 4 mukainen luokka cTabs

   cTabs
  +-----------------------+
  | tabs                  |
  | +---+---+---+---+---+ | 
  | | 8 | 8 | 8 | 8 | 8 | |
  | +---+---+---+---+---+ | 
  +-----------------------+

Arvostelusta

piirretty taulukko ja luokan raamit 1/2 p
pienillä puutteilla (esim taulun nimi puuttuu tms) +
luokkaan piirretty vakio MAX_TABS tai muita ylimääräisiä attribuutteja +

b) täydennä luokan muodostaja (constructor) toimivaksi (max 1p)

#include 
... 

   cTabs(int deftab=0) {
     for (int i=0; i < MAX_TABS; i++) {
       tabs[i] = abs(deftab);           // tai jokin käsittely negatiivisille luvuille
     }                                  // unsigned(deftab) antaa ylivuodon, eikä ole 
   }                                    // välttämättä haluttu tulos

Arvostelusta

Suurin osa ei ollut huomannut, että taulukon alkiot ovat tyyppiä unsigned int ja parametrina saatu tyyppi oli int. Sijoituksessa pitää ottaa jollain tavalla huomioon, että parametrina saadun int-muuttujan arvo voi olla negatiivinen. Jollei negatiivisuutta oltu käsitelty, sai alustuksesta 1- pistettä (e-kohdassa ei olla rokotettu siitä, että ei huomattu "väärää" sijoitusta).

Jos lisäksi oli joitain syntaksi-, ajatus- tms. virheitä sai tehtävästä 1/2 pistettä.

c) täydennä lisää-metodi toimivaksi (max 1.5 p)

  void lisaa(int i, const string &sana) {
    if (i < 0 || i > MAX_TABS-1) return;
    unsigned int pituus = strlen(sana.c_str());
    if ( tabs[i] < pituus ) tabs[i] = pituus;
  }

Arvostelu

taulukon arvoalueen tarkastus 1/2 p
merkkijonon pituuden selvittäminen 1/2 p
oikea vertailu ja alustus 1/2 p

Joillain oli lisaa-metodin tarkoitus ymmärretty väärin, jolloin lisaa- metodiin oli kirjoitettu silmukoita ym. Jos merkkijonon pituuden laskemiseen oli väärä metodi eikä metodia oltu kommentoitu, on merkkijonon pituuden selvittämisen osuus 0 p.

Pienistä syntaksivirheistä on sakotettu enintään -. Loogisista virheistä on sakotettu enemmän.

d) Tarvitseeko destruktorin? (max 1 p)

Ei tarvitse. Koska olio ei sisällä mitään dynaamisesti varattuja muuttuujia, tuhoutuvat muuttujat olion destruktorissa (joka on olemassa automaattisesti jokaisella oliolla!).

Arvostelu

oikea arvaus 0.5 p
oikea perustelu 0.5 p

Riittävä peruste on ollut, että kaikki muuttujat (taulukko) on olion sisällä. Riittävä peruste ei ole se, että oliosta ei lähde nuolia (osoittimia) ulos. Ajatelkaa esim. harkan cNaytto-luokkaa. Sillä on osoitin cKerho:on, mutta destruktori ei siinäkään tapauksessa ole pakollinen, sillä cNaytto ei ole varannut dynaamisesti muistia cKerhoa varten (sehän vain sai parametrina kerhon jota pitää käyttää, eikä edes saa mennä tuhoamaan kerhoa sen jälkeen kun itse lopettaa hommansa).

Joillain näytti olevan hukassa koko destruktorin käsite! Kerratkaa ihmeessä esim monisteesta tai olio-kertauksesta.

e) luokan muuntaminen dynaamiseksi (max 3 p)

Tähän tehtävään oli ainakin kaksi erilaista (periaatteessa) oikeaa vastausta. Voidaan käyttää tietorakennetta i)

     cTabs
    +------------+
    | lkm 5      |
    | tabs  o    |
    +-------+----+
            |
            v
        +---+---+---+---+---+
        | 8 | 8 | 8 | 8 | 8 |
        +---+---+---+---+---+      
 

tai ii)


     cTabs
    +------------+
    | maxlkm 5   |
    | lkm 5      |
    | tabs  o    |
    +-------+----+
            |
            v
        +---+---+---+---+---+
        | o | o | o | o | o |
        +-+-+-+-+-+-+-+-+--++
          |   |   |   |    |
       +--+  ++   ++  +--+ +---+
       v     v     v     v     v
     +---+ +---+ +---+ +---+ +---+
     | 8 | | 8 | | 8 | | 8 | | 8 |
     +---+ +---+ +---+ +---+ +---+    

Näistä vaihtoehto ii) ei kuitenkaan ole kovin järjevä, sillä luokan idea on täyttää kaikki taulukkonsa paikat (harkka on tässä suhteessa erilainen!). Luokka vie enemmän muistia kuin vaihtoehto i) ja sen käyttämisessä saa olla aavistuksen huolellisempi. Hyöty varrattuna vaihtoehtoon i) ? Enpä keksi. Piirtämiseenkin meni puota kauemmin aikaa.

Vaihtoehdon i) mukainen mallikoodi

/* Ohjelmoinnin 2002
   Välikoe 1. Teht 4 e
   19.3.2002 Minna Hillebrand
*/

//---------------------------------------------------------------------------

#include 
#include 
#include 
using namespace std;

class cTabs {
  unsigned int *tabs;
  int lkm;                             // tarvitaan muistiin alkioden maara
public:
  cTabs(int deftab=0, int lkm=5) {
    this->lkm = 0;
    tabs = new unsigned int[lkm];      // dynaaminen muistinvaraus
    if (tabs != 0) {
      this->lkm = lkm;
      for (int i=0; i < lkm; i++) {
        tabs[i]=abs(deftab);
      }
    }
  }
  ~cTabs() {
    delete [] tabs;                    // taulukon vapauttaminen
  }

  // copy constructor
  cTabs(const cTabs &toinen) {         
    this->lkm = 0;
    tabs = new unsigned int[toinen.getLkm()];
    if (tabs != 0) {
      this->lkm = toinen.getLkm();
      for (int i=0; i < lkm; i++) {
        tabs[i] = toinen.tab(i);
      }
    }
  }

  // sijoitusoperaattori
  cTabs &operator=(const cTabs &toinen) {
    if (this != &toinen) { // ei sijoitusta mina = mina
      delete [] tabs;
      tabs = new unsigned int[toinen.getLkm()];
      if (tabs) {
        for (int i=0; i < toinen.getLkm(); i++)
          tabs[i] = toinen.tab(i);
        this->lkm = toinen.getLkm();
      }
    }
    return *this;
  }

  void lisaa(int i, const string &sana) {
    if (i < 0 || i > getLkm()-1) return;         // i:n arvoalue
    unsigned int pituus = sana.length();  // huomaa pituuden tyyppi!
    if ( tab(i) < pituus ) tabs[i] = pituus;
  }

  unsigned int tab(int i) const {
    if (i < 0 || i > getLkm()-1) return 0;       // i:n arvoalue
    return tabs[i];
  }

  void tulosta() const {                         // testausta varten
    for (int i=0; i < getLkm(); i++)             // ei pyydetty tentissä
      cout << (i+1) << ". " << tabs[i] << endl;
  }

  int getLkm() const { return lkm; }             // ei pyydetty, mutta hyvä olla olemassa

};

//---------------------------------------------------------------------------

int main()
{
  cTabs tabs(-8, 5);
  tabs.tulosta();

  { cTabs kopio;
    kopio = tabs;
    kopio.tulosta();
    kopio.lisaa(1, "lepakot nukkuu puussa");
    kopio.tulosta();
    tabs.tulosta();
  }  

  tabs.lisaa(2, "kissa istuu");
  tabs.lisaa(1, "kana kotkottaa");
  tabs.lisaa(1, "kissa syö hiirtä");
  tabs.lisaa(1, "kissa");
  tabs.lisaa(9, "kukko kiekuu");
  tabs.tulosta();

  return 0;
}
//---------------------------------------------------------------------------

Arvostelusta

kuva joka vastaa luokan esittelyä 1/2 p
asianmukainen konstruktori 1/2 p
destruktori 1/2 p
copy constructor ja sijoitusoperaattori 1/2 p
metodit toteutettu oikein 1/2 p
parametrin i arvoalue muistettu tarkastaa 1/2 p

Arvostelussa painotettu sitä, että on käytetty new:tä muistinvaraukseen ja vastaavasti tuhottu taulukko deletellä. Tehtävä joka ei käytä dynaamista muistinvarausta, ei ole ilman erityisansioita päässyt yli 1 pisteen.