2.10.3 Tietueet funktion parametrina ja paluuarvona

Tietuetyyppisiä muuttujia voidaan käyttää myös funktioiden parametreina ja paluuarvoina aivan kuin esimerkiksi kokonaislukumuuttujia. Samoin viittausoperaattoria & voidaan käyttää tietueille normaaliin tapaan. Jos siis halutaan, että funktion parametrille tehdyt muutokset välittyvät kutsuvaan ohjelmanosaan, käytetään viittausta.

Seuraava esimerkkiohjelma lukee päivämäärän ja sitten laskee, mikä viikonpäivä on kyseessä. Laskukaava on hieman monimutkainen, mutta siitä ei tarvitse välittää; pääasiana tässä esimerkissä on esitellä, miten tietuemuuttujia käsitellään.

/* *********************************************************
VKONPV2.CPP 
  Lukee ensin näppäimistöltä päivämäärän, ja sitten laskee
  ja tulostaa näytölle vastaavan viikonpäivän.
********************************************************* */
#include <iostream.h> 

struct paivamaara { 
  int pp, kk, vvvv;
}; 

void lue_paivamaara(paivamaara &pvm) { 
  cout << "Anna päivämäärä muodossa pp kk vvvv > "; 
  cin  >> pvm.pp >> pvm.kk >> pvm.vvvv; // järkevyys pitäisi tarkistaa! 
} 

int laske_viikonpaiva(paivamaara pvm)
{
  int a, b, c, dd;

  if (pvm.kk <= 2) {         // ei haittaa vaikka kenttämuuttujien arvoja
    pvm.kk = pvm.kk + 10;    //  muutetaan; muutokset eivät välity tämän
    pvm.vvvv = pvm.vvvv - 1; //  funktion ulkopuolelle
  }
  else
    pvm.kk = pvm.kk - 2;
  a = pvm.vvvv/100;
  b = pvm.vvvv%100;
  c = (13*pvm.kk - 1)/5 + a/4 + b/4;
  dd = pvm.pp - 2*a + b + c;
  while (dd < 0) // muunnetaan dd ei-negatiiviseksi, sillä %-operaattoria
    dd = dd + 7; //  on syytä käyttää vain ei-negatiivisille operandeille;
                 //  muutoin tulos riippuu kääntäjästä
  return (dd%7);
}

void tulosta_viikonpaiva(int vkonpv, paivamaara pvm)
{
  cout << pvm.pp << "." << pvm.kk << "." << pvm.vvvv << " on ";
  switch (vkonpv) {
    case 1:
      cout << "maanantai." << endl;
      break;
    case 2:
      cout << "tiistai." << endl;
      break;
    case 3:
      cout << "keskiviikko." << endl;
      break;
    case 4:
      cout << "torstai." << endl;
      break;
    case 5:
      cout << "perjantai." << endl;
      break;
    case 6:
      cout << "lauantai." << endl;
      break;
    case 0:                         // tapaukset vkonpv < 0 ja
      cout << "sunnuntai." << endl; //  vkonpv > 6 eivät mahdollisia,
      break;                        //  siksi ei default-osaa
  }
}

int main(void)
{
  paivamaara tanaan;
  int viikonpaiva;

  lue_paivamaara(tanaan);
  viikonpaiva = laske_viikonpaiva(tanaan);
  tulosta_viikonpaiva(viikonpaiva, tanaan);

  return 0;
}

Esimerkkiajo:

Anna päivämäärä muodossa pp kk vvvv > 13 11 1987
13.11.1987 on perjantai.

Muuta funktiota lue_paivamaara siten, että syöttötiedot tarkistetaan ja vain järkevät arvot hyväksytään.

Jos funktion parametrissa ei käytetä viittausta, niin funktion kutsussa argumenttina annetun lausekkeen arvo kopioituu sitä vastaavaan parametriin, joka on siis funktion paikallinen muuttuja. Tämä koskee myös tietueparametreja. Yksinkertaisten muuttujien tapauksessa kopioinnista ei yleensä ole mitään haittaa. Sen sijaan tietuemuuttujat voivat olla hyvin "suuria" (eli vaativat paljon tilaa), joten niiden tapauksessa kopiointia voi tapahtua hyvinkin paljon. Tästä syystä monet ohjelmoijat käyttävät tietueparametreille aina viittausta riippumatta siitä, muutetaanko niiden arvoja vai ei.

Tietuetta voidaan käyttää paluuarvona tavalliseen tapaan. Esimerkiksi, määritellään funktio

paivamaara seuraava_paiva(paivamaara pvm)
{
  pvm.pp++;
  if (pvm.pp > 30) {   // tässä kalenterissa jokaisessa
    pvm.pp = 1;        //  kuukaudessa on 30 päivää!
    pvm.kk++;
    if (pvm.kk > 12) {
      pvm.kk = 1;
      pvm.vvvv++;
    }
  }
  return pvm;
}

jota voitaisiin kutsua seuraavasti:

paivamaara tanaan = {30, 7, 1992}, huomenna;
...
huomenna = seuraava_paiva(tanaan);