Ohjelmointi++ 2002/ 4.3

Demo 7


Muista ettei tehtäviä lasketa kuin max. 10 kerrallaan, joten jos teet bonus/guru-tehtäviä, niin voit säästää aikaasi jättämällä muutaman "tavallisen" tekemättä. Bonus-tehtävät on täysin mahdollista tehdä kurssin tiedoilla. Tämän kerran Guru-tehtäväkin on mahdollista tehdä, se vaatii vain hieman miettimistä.


1*.
Mikä (tai mitkä) string.h kirjaston (ks. liite lopussa) funktio sopisi seuraavan ongelman ratkaisemiseen ja miten (kirjoita malli kutsusta):
a)
Onko jonossa jono muita kirjaimia kuin joukon k kirjaimet
jono="kissa" k="aik" -> on, k="aiks" -> ei ole
b)
Missä on jonon viimeinen '\'.
       "C:\OMAT\OHJELMOI\VESA\KOE.C"  -> 
       osoitin osoittamaan viimeiseen '\'-merkkiin, 
       eli jonon \KOE.C:n alkuun.
c)
Onko jonossa jokin kirjain joukosta k
jono="kissa" k="ibm" -> on , k="pc" -> ei ole
2.
Katso mjonot.c -aliohjelmista mitä kutsuja käyttäen voisit ratkaista seuraavat ongelmat (löytyy hakemistosta \kurssit\cpp\ali):
a)  onko "  matti*  " sama kuin "Matti Nykänen"?  
    (vastaus: on.  Huomaa jokerimerkki, välilyönnit, sekä
isot ja pienet kirjaimet)
b)  Paljonko jonossa "Kissa istuu puussa" on yhteensä
    merkkejä "a-j" tai "r-w"  ("a-j" == "abcdefghij")
    (vastaus: 2*a + 2*i +5*s + 1*t + 4*u = 14)

3.
Monisteen tehtävä 14.139 suurin kirjeen paino, if-toteutus
4*.
14.139 suurin kirjeen paino, taulukkoon pohjautuva toteutus. Koeta saada hintojen muuttaminen mahdollisimman helpoksi.
5.
14.141 palindromi.
6*.
Kirjoita kaksi eri aliohjelmaa (toinen string-jonoille ja toinen char *-jonoille) tuhoa_lopusta, jotka loogisessa mielessä "poistavat" merkkijonon n viimeistä merkkiä (muista virhetilanteet!):
char s[]="Kissa istuu";
tuhoa_lopusta(s,3);               /* => s = "Kissa is" */
string st("Kissa istuu");
tuhoa_lopusta(st,3);              // => st= "Kissa is" 

7*.
Täydennä seuraava C-ohjelma kirjoittamalla pääohjelman kommenteissa kuvatut sijoitukset. Piirrä aluksi kuva kummastakin tietueesta (toni ja matti) sijoituksen jälkeen
/* tonitiet.c */
/* Malli tietueesta tietueessa
#include <stdio.h>

typedef struct { double pituus; /* hyppyjen pituudet metreinä */ double tuomarit[5]; /* tuomaripisteet */ double pisteet; /* Yhteistulos */ } Kierros_tyyppi;

typedef struct { Kierros_tyyppi kierros[2]; double lopputulos; } Tulos_tyyppi;

typedef struct { char nimi[8]; int nro; Tulos_tyyppi tulos; } Kilpailija_tyyppi;

int main(void) { Kilpailija_tyyppi toni,matti; /* Kirjoita miten C-kielellä suoritetaan sijoitukset:

toni: nimi <- "Toni N" nro <- 3 1. kierroksen pituus <- 107 2. kierroksen tuomareiden pisteet <- 19,18,19.5,18,20 matti: nimi <- "Matti H" nro <- 7 2. kierroksen pituus <- 109 1. kierroksen pisteet <- 125 Lopputulos <- 251

Esimerkki: toni.tulos.kierros[0].pituus = 107; */ ... return 0; }

8*.
Kirjoita aliohjelmat paras (palauttaa reaalilukutaulukon suurimman luvun), huonoin (palauttaa reaalilukutaulukon pienimmän luvun) ja summa (palauttaa reaalilukutaulukon summan). Näitä käyttäen kirjoita aliohjelma summa_huonoin_ja_paras_pois, joka palauttaa reaalilukutaulukon summan kun siitä otetaan huonoin ja paras tulos pois (sopii esim. mäkikisan arvosteluun).
B1-2
Astiapelissä (astia3.cpp) voitaisiin tehdä lopun automaattista tarkistusta auttamaan luokka, jota voitaisiin käyttää seuraavasti (sovitaan että astioiden tilavuudet voivat olla vain kokonaislukuja):
cEsiintymat esiintymat(1,13);  // laskee lukujen 1-13 esiintymiä
esiintymat.lisaa(0);  // ei vaikuta, koska 0 ei ole välillä [1,13]
esiintymat.lisaa(8);  // lisää yhden esiintymän luvun 8 kohdalle.
esiintymat.lisaa(5);  // lisää yhden esiintymän luvun 5 kohdalle.
esiintymat.tulosta_loydetyt(cout); cout << endl;  
            // tulostaa: 5 8
esiintymat.tulosta_ei_loydetyt(cout); cout << endl;  
            // tulostaa: 1 2 3 4 6 7 9 10 11 12 13
int loydettyja = esiintymat.getLoydettyja();
cout << "Löydettyjä on " << loydettyja << endl;  
            // tulostaa: Löydettyjä on 2

Toteuta luokka cEsiintymat ja testaa sitä em. kutsuilla.
G1-2
Edelleen astiapeliin. Löydetyt esiintymät on "helppo" tarkistaa jos tiedetään että käyttöastioita on 2 kappaletta. Mutta jos astioita on lkm-kappaletta, niin testaaminen meneekin vaikeammaksi. Hahmottele apuluokka, jota voitaisiin käyttää edellisen tehtävän cEsiintymat-luokan kanssa apuna käymään läpi kaikki summakombinaatiot, joita astioista voisi muodostaa. Eli jos meillä olisi vaikkapa astioita 3 kappaletta ja niissä olisi nestettä 3, 5 ja 9 litraa, niin saisimme niillä aikaiseksi summakombinaatiot (järjestys ei ole oleellinen):
3       (3+0+0)
5       (0+5+0)
8       (3+5+0)
9       (0+0+9)
12      (3+0+9)
14      (0+5+9)
17      (3+5+9)
Aloita hahmottelu miettimällä kuinka voisit alustaa luokan, mitä metodeja tarvittaisiin ja miten kutsuisit metodeja (vrt. edellinen tehtävä, olkoon luokan nimi vaikkapa cKombinaatiot).

string.h

void *memchr(const void *s, int c, size_t n);

Hakee c:tä s:stä alkaen enintään n tavua. Palauttaa osoittimen c:n ensimmäiseen esiintymään s:ssä jos löytyi, muuten NULL.

int memcmp(const void *s1, const void *s2, size_t n);

Vertaa jonoista s1 ja s2 enintään n tavua. Palauttaa < 0 jos s1 on pienempi kuin s2 == 0 jos s1 on sama kuin s2 > 0 jos s1 on suurempi kuin s2

void *memcpy(void *dest, const void *src, size_t n);

Kopioi n tavua alkaen paikasta src paikkaan dest. Palauttaa osoittimen dest:iin. Jos src ja dest menevät pituudella n päällekkäin, toiminta on määrittelemätön.

void *memmove(void *dest, const void *src, size_t n);

Toimii kuten memcpy, mutta kopiointi suoritetaan kokonaisena lohkona, jolloin ei haittaa vaikka dest ja scr menevät päällekkäin.

void *memset(void *s, int c, size_t n);

Asettaa n tavua alkaen paikasta s tavuksi c. Palauttaa s:n.

char *strcat(char *dest, const char *src);

Liittää merkkijonon alkaen paikasta src merkkijonon dest perään. Palauttaa osoittimen dest:iin.

char *strchr(const char *s, int c);

Palauttaa osoittimen merkin c ensimmäiseen esiintymään merkkijonossa s. NULL:n, jos ei merkkiä löydy.

int strcmp(const char *s1, const char *s2);

Vertaa kahta merkkijonoa etumerkittömänä. Paluuarvo kuten memcmp:ssä. (Siis myös Turbo C:ssä 'A'<'Ä'!)

char *strcpy(char *dest, const char *src);

Kopioi merkkijonon src paikkaan dest. Palauttaa osoittimen dest:iin.

size_t strcspn(const char *s1, const char *s2);

Palauttaa ensimmäisen s1:n s2:ssa esiintyvän merkin indeksin s1:ssä. Jos ei löydy, palauttaa s1:en pituuden.

char *strerror(int errnum);

Palauttaa osoittimen virhenumeroa errnum vastaavaan virheen selitykseen.

size_t strlen(const char *s);

Palauttaa merkkijonon s pituuden ilman \0-merkkiä.

char *strncat(char *dest, const char *src, size_t maxlen);

Kuten strcat, mutta liitetään enintään maxlen merkkiä.

int strncmp(const char *s1, const char *s2, size_t maxlen);

Kuten strcmp, mutta verrataan enintään maxlen merkkiä.

char *strncpy(char *dest, const char *src, size_t maxlen);

Kuten strcpy, mutta kopioidaan enintään maxlen merkkiä.

char *strpbrk(const char *s1, const char *s2);

Palauttaa osoittimen s1:n ensimmäiseen merkkiin, joka sisältyy merkkijonoon s2. Jos ei löydy yhtään, palautetaan NULL. (vrt. strcspn).

char *strrchr(const char *s, int c);

Palauttaa osoittimen merkin c viimeiseen esiintymään merkkijonossa s. Palauttaa NULL:n, jos ei löydy yhtään.

size_t strspn(const char *s1, const char *s2);

Palauttaa ensimmäisen s1:n indeksin jossa paikassa ei ole s2:en merkkiä.

char *strstr(const char *s1, const char *s2);

Palauttaa osoittimen paikkaan s1:ssä, josta alkaen löytyy merkkijono s2. Palautetaan NULL, jos s2:sta ei löydy s1:stä.

char *strtok(char *s1, const char *s2);

s2 määrittelee erotinmerkit. strtok jakaa s1:n erotinmerkkien erottelemiin osiin. Ensimmäisellä kutsulla strtok palauttaa osoittimen ensimmäiseen osaan ja asettaa erotinmerkin kohdalle NULn (\0). Seuraavilla kutsuilla s1:n tilalla käytetään NULL:a, edellisestä merkkijonosta palautetaan seuraavaan osaan osoittava osoitin. Kun jonossa ei ole osia, palautetaan NULL.

Esim: strtok("ab,c,d",",") ==> "ab" strtok(NULL,",") ==> "c" strtok(NULL,",") ==> "d" strtok(NULL,",") ==> NULL

int strcoll(char *s1, char *s2); (Turbo-C:ssä kuten strcmp)

Kuten strcmp mutta osaa verrata kansallisia merkkejä oikein LC_COLLATE:n mukaan.

size_t strxfrm(char *s1, char *s2,size_t n); (Turbo-C:ssä kuten strncpy)

Kuten strncpy (palauttaen kuitenkin kopioitujen merkkien määrän), mutta muuntaa merkkijonon s1, siten että tulosmerkkijonossa s2 on kansalliset merkit korvattu LC_COLLATE:n mukaan. Verrattaessa muunnettuja merkkijonoja strcmp -funktiolla, vertailu menee oikein kansallisten merkkien kohdalla.