Ohjelmointi++ 2001/ 21.3

1. välikoe


Jokainen tehtävä omalle konseptille. Yhdeltä konseptilta arvostellaan vain YKSI tehtävä. Pöytätestille on oma lomake. Tarvittaessa liitä pöytätestiinkin mukaan konsepti. Aikaa 4 tuntia!

Vastaa 4 tehtävään (yht. max 24 pistettä). Jos vastaat useampaan, arvostellaan 4 huonointa. Jos ohjelmatehtävissä käytät standardifunktioita tai metodeja, muttet muista tarkkaan funktion tai metodin nimeä, kirjoita "kuvittelemasi" esittely funktiolle tai metodilla.

1. Pöytätesti

Mitä seuraava ohjelma tulostaa ja mitä ovat muuttujien arvot ohjelman loppuessa? Tutki PÖYTÄTESTIN avulla! (6p)
// vk2001.cpp
#include <iostream>
#include <string>
/* 04 */ using namespace std;
/* 05 */ string piilossa;
/* 06 */ int color = 2;
/* 07 */ const int petaja = 6;
/* 08 */ 
/* 09 */ class cHiihtaja {
/* 10 */   double vauhti;
/* 11 */ public:
/* 12 */   cHiihtaja() { vauhti = 16.2; color++; }
/* 13 */   ~cHiihtaja() {
/* 14 */     if ( vauhti > 20 ) color += petaja;
/* 15 */     cout << "en oo! "; nayte();
/* 16 */   }
/* 17 */   void laakari(int hemo=0) {
/* 18 */     vauhti += hemo;
/* 19 */   }
/* 20 */   void nayte() {
/* 21 */     cout << color << " " << vauhti << "\n"; vauhti += 1;
/* 22 */   }
/* 23 */ };
/* 24 */ 
/* 25 */ void voitele(cHiihtaja isoniemi, int hess=2)
/* 26 */ {
/* 27 */   isoniemi.laakari(hess);
/* 28 */   isoniemi.nayte();
/* 29 */ }
/* 30 */ 
/* 31 */ int main(void)
/* 32 */ {
/* 33 */   cHiihtaja tyokalumetsa;
/* 34 */   int color = 2*petaja;
/* 35 */   tyokalumetsa.laakari(color);
/* 36 */   tyokalumetsa.nayte();
/* 37 */   {
/* 38 */     cHiihtaja pulmunen;
/* 39 */     pulmunen.laakari();
/* 40 */     pulmunen.nayte();
/* 41 */     voitele(tyokalumetsa,color++);
/* 42 */   }
/* 43 */   tyokalumetsa.nayte();
/* 44 */   return 0;
/* 45 */ }

2. Algoritmit ja merkkijonot

Merkkijonossa on välilyönnein toisistaan erotetuja sanoja.
(esim: hessu hopo syö hessburgerissa megahemohesshampurilaista)
a)
Kirjoita algoritmi, jolla saadaan selville mikä on merkkijonon pisin sana, jossa on osajono "hess". (Algoritmin pienimpänä "yksikkönä" luennolla käytettyt funktiot/C++:n merkkijonoista löytyvät metodit. Eli ei tarvitse etsiä merkki kerrallaan.)(2p)
b)
Kirjoita C++:n merkkijonoja käyttäen (string) funktio mika_pisin, joka palauttaa merkkijonon (rivin) sen sanan, joka on pisin parametrinä vietyä jonoa sisältävä sana. Luennon erota-funktiota saa käyttää. Jos tarvitset vielä jotakin muuta funktiota tai metodia (ks. liite), niin kirjoita siitä esittelyrivi (prototyyppi) ja kommentoi mitä funktio tekee. Esimerkin rivistä palautettaisiin tietysti "megahemohesshampurilaista" jos kysytään jonon "hess" perusteella. Erikoistapausten (ei yhtään tai yhtämonta) tulkinnasta saat päättää itse, kunhan funktio käsittelee ne jollakin järkevällä tavalla. Isot ja pienet kirjaimet ovat eri asia ("hess" != "Hess"). (4p)


3. Tiedostot

Kirjoita ohjelma (ohjelmointikieli vapaa, kunhan siihen löytyy implementaatio PC-koneille ja olet valmis esittmään ohjelmasi toiminnan tentin jälkeen ko. implementaatiolla), joka lukee kaikki rivit tiedostosta, jossa on tekstiä. Ohjelman pitää tulostaa kunkin rivin sanoista pisin sellainen, jossa on osajono "ss" ja lopuksi se rivi, jossa oli koko tiedoston pisin jonon "ss" sisältävä sana.(6p)

Tiedostosta
Kissa istuu puussa!
Opiskelija sihissee kysymyksiä pähkäillessään.
Katolla kukko kiekuu.
tulostuisi (erkoistapaukset päätetty tuossa käsitellä niin, että ensimmäinen otetaan):
puussa
pähkäillessään.
Katolla
Opiskelija sihissee kysymyksiä pähkäillessään.


4. C++ ja dynaamisuus

Olkoon luokkaesittelyt (... tarkoittaa "paljon" koodia) ja pääohjelma:

class cTaulukko1 {
  int lkm;
  int alkiot[5]; 
public:
...
};

class cTaulukko2 { int max_koko; int lkm; int *alkiot; public: ... };

class cTaulukko3 { int max_koko; int lkm; int **alkiot; public: ... };

class cTaulukko4 { int lkm; int *alkiot[5]; public: ... };

int main(void) { cTaulukko1 luvut(5); luvut.lisaa(2001); luvut.lisaa(22); // Kuva tästä tilanteesta luvut.tulosta(); return 0; }



Tarkoitus on että pääohjelmassa voidaan vaihtaa cTaulukko1:n tilalle mikä tahansa edellistä 4:stä luokasta ja pääohjelma toimii aina samalla tavalla (eli tulostaa 2001 22).
a)
Piirrä kuva kustakin tietorakenteesta juuri ennen tulosta-metodin kutsua.(2p)
b)
Missä luokissa on PAKKO kirjoittaa itse jonkinlainen Copy Constructor ja sijoitusoperaattori? Perustelu! Missä luokissa on pakko kirjoittaa destruktori?(1p)
c)
Kirjoita konstruktori kahteen (2) valitsemaasi luokkaan.(2p)
d)
Kirjoita lisaa-metodi kahteen (2) valitsemaasi luokkaan. (Taulukon koon suurentamista ei tarvitse tehdä.)(1p)


5. Luokat

Kirjoita luokka cHavainto jota voidaan käyttää kuten seuraavassa pääohjelmassa. Kirjoitettava koko luokka (attribuutit, kaikki metodit yms.) Riittää kuitenkin tehdä "demovastaus", eli ei tarvitse pitää kirjaa mitä erikokoisia havaintoja on olemassa, vaan "toivotaan" että käyttäjä poistaa saman kokoisia "möykkyjä" kuin on laittanutkin.(5p)

int main(void)
{
  cHavainto tammikuun_lammot;
  cHavainto helmikuun_lammot;
  cHavainto maaliskuun_lammot;
  cHavainto alkuvuosi;                // Tulostuu:
  tammikuun_lammot.lisaa(-24.2);
  tammikuun_lammot.tulosta();         // Havaintoja: 1 keskiarvo: -24.2
  tammikuun_lammot.poista(-24.2);
  tammikuun_lammot.tulosta();         // Havaintoja: 0 keskiarvo: 0
  tammikuun_lammot.lisaa(-14.2);
  tammikuun_lammot.lisaa(-20.5);
  helmikuun_lammot.lisaa(-30.7);
  helmikuun_lammot.lisaa(-7.5);
  maaliskuun_lammot.lisaa(-18.6);
  maaliskuun_lammot.lisaa(2.7);
  maaliskuun_lammot.lisaa(-5.7);
  alkuvuosi.lisaa(tammikuun_lammot);
  alkuvuosi.lisaa(helmikuun_lammot);
  alkuvuosi.lisaa(maaliskuun_lammot);
  tammikuun_lammot.tulosta();         // Havaintoja: 2 keskiarvo: -17.35
  helmikuun_lammot.tulosta();         // Havaintoja: 2 keskiarvo: -19.1
  maaliskuun_lammot.tulosta();        // Havaintoja: 3 keskiarvo: -7.2
  alkuvuosi.tulosta();                // Havaintoja: 7 keskiarvo: -13.5
  return 0;
}

Voiko luokka cHavainto pitää kirjaa pienimmästä ja suurimmasta arvosta ilman taulukkoa? Perustelut!(1p)

Liitteitä

Ote string:in helpistä. size_type on positiivinen kokonaisluku, basic_string on kantaluokka stringille. charT on merkkityyppi (joka stringin tapauksessa on char).

size_type
find (const basic_string& str, size_type pos = 0) const;

Searches for the first occurrence of the substring specified by str in this string, starting at position pos. If found, it returns the index of the first character of the matching substring. If not found, returns npos. Equality is defined by traits::eq().

size_type
find (const charT* s, size_type pos, size_type n) const;
size_type
find (const charT* s, size_type pos = 0) const;
size_type
find (charT c, size_type pos = 0) const;

Searches for the first sequence of characters in this string that match a specified string. The variations of this function return, respectively:

find(basic_string(s,n), pos)
find(basic_string(s), pos)
find(basic_string(1, c), pos)

size_type
find_first_of(const basic_string& str,
size_type pos = 0) const;

Searches for the first occurrence at or after position pos of any element of str in this string. If found, the index of this matching character is returned. If not found, npos is returned. Equality is defined by traits::eq().

Non-member Functions

template <class Stream, class charT, class traits,
class Allocator>
basic_istream<charT, traits>
getline(basic_istream<charT, traits> is,
<charT, traits allocator> str, charT delim);

An unformatted input function that extracts characters from is into str until npos - 1 characters are read, the end of the input sequence is reached, or the character read is delim. The characters are read using traits::char_in().


Palanen mjonotpp.h:n kommenteista:

**    erota                  - laittaa merkkijonon kahtia valitun merkin
**                             kohdalta
**    erota                  - laittaa merkkijonon kahtia ensimmäisen
**                             valitun merkin kohdalta

ja koodista: //------------------------------------------------------------------------------ inline vstring erota(vstring &jono, char merkki=' ',bool etsi_takaperin=false) // Erottaa jonosta valitun merkin kohdalta alkuosan ja loppuosan. // Alkuosa palautetaan funktion nimessä ja loppuosa jätetään // jonoon. Merkin etsimissuunta voidana valita (oletuksena alusta päin). // Jos merkkiä ei löydy, palautetaan koko jono ja tyhjennetään jono. // Käyttöesimerkki: olkoon aluksi string jono,s; // 1) jono = "123 456"; s = erota(jono); => jono == "456" s == "123" // 2) jono = "123"; s = erota(jono); => jono == "" s == "123" // 3) jono = "1 2 3"; // while ( jono != "" ) cout << erota(jono) << ","; => tulostaa 1,2,3, // { size_t p; if ( !etsi_takaperin ) p = jono.find(merkki); else p = jono.rfind(merkki); vstring alku = jono.substr(0,p); if ( p == vstring::npos ) jono = ""; else jono.erase(0,p+1); return alku; }

vstring erota(vstring &jono, const vstring &merkit,bool etsi_takaperin=false); ... //------------------------------------------------------------------------------ vstring erota(vstring &jono, const vstring &merkit,bool etsi_takaperin) // Erottaa jonosta valittujen merkkien kohdalta alkuosan ja loppuosan. // Alkuosa palautetaan funktion nimessä ja loppuosa jätetään // jonoon. Merkin etsimissuunta voidana valita (oletuksena alusta päin). // Jos merkkiä ei löydy, palautetaan koko jono ja tyhjennetään jono. // Käyttöesimerkki: olkoon aluksi string jono,s; // 1) jono = "123 456"; s = erota(jono," "); => jono == "456" s == "123" // 2) jono = "123"; s = erota(jono,";"); => jono == "" s == "123" // 3) jono = "1;2 3"; s = erota(jono," ;"); => jono == "2 3" s == "1" // { size_t p; if ( !etsi_takaperin ) p = jono.find_first_of(merkit); else p = jono.find_last_of(merkit); vstring alku = jono.substr(0,p); if ( p == vstring::npos ) jono = ""; else jono.erase(0,p+1); return alku; }