2.4.8 Viittaukset funktiosta kutsuvaan yksikköön

Tähän mennessä on käsitelty funktioita, jotka saavat syöttötietoa parametrien välityksellä ja jotka palauttavat nimellään arvon kutsuvaan yksikköön. Tietoa funktiosta voi palauttaa kuitenkin myös parametrien välityksellä.

Kirjoitetaan funktio vaihda, jolle viedään parametreina kaksi kokonaislukumuuttujaa, ja tarkoituksena olisi, että muuttujien arvot vaihdetaan keskenään. Ensimmäinen yritys näyttää seuraavalta:

/* *********************************************************
VAIHDA0.CPP
  Lukee arvot kahteen kokonaislukumuuttujaan, vaihtaa ne
  keskenään ja tulostaa muuttujien arvot.
  HUOM: Ei toimi niin kuin pitäisi!
********************************************************* */

#include <iostream.h>

/* Funktion pitäisi vaihtaa parametrien arvot keskenään, mutta
   funktiossa tehdyt muutokset eivät välity kutsuvaan ohjelmaan. */
void vaihda(int a, int b)
{
  int apu;

  apu = a;
  a = b;
  b = apu;
}

int main(void)
{
  int eka, toka;

  cout << "\n\n";
  cout << "Anna kaksi kokonaislukua > ";
  cin >> eka >> toka;

  cout << "Luvut ennen vaihtoa:   " << eka << " " << toka << endl;
  vaihda(eka, toka);
  cout << "Luvut vaihdon jälkeen: " << eka << " " << toka << endl;

  return 0;
}

Kokeillaan:

Anna kaksi kokonaislukua > 12 67
Luvut ennen vaihtoa:   12 67
Luvut vaihdon jälkeen: 12 67

Mitä tapahtui?

Kun ohjelma suorittaa funktion kutsun, tapahtuu suurin piirtein seuraavaa:

  1. Kutsuvan yksikön suoritus pistetään hetkeksi "jäihin".
  2. Keskusmuistista varataan funktiolle oma työalue.
  3. Mikäli funktiolla on parametreja, varataan funktiolle osoitetusta työalueesta tilaa kunkin parametrin tyypin vaatima määrä ja kopioidaan argumenttilistaan kirjoitettujen tietoalkioiden arvot niille varattuun tilaan.
  4. Suoritetaan funktion sisältämät lauseet ja mahdollisesti palautetaan kutsuvalle yksikölle paluuarvo.
  5. Funktion suorituksen päättyessä sille varattu työtila vapautetaan muiden funktioiden käyttöön.

Olennaista on huomata, että funktion ja sitä kutsuvan yksikön käyttämät työtilat ovat täysin erilliset. Funktiossa käsiteltävät parametreina tuodut arvot ovat kopioita kutsuvan ohjelman arvoista. Näin ollen edellisessä esimerkissä funktion parametreina esiintyviin muuttujiin kohdistuvat operaatiot eivät vaikuta kutsuvassa yksikössä esiintyvien muuttujien arvoihin millään lailla.

Ratkaisu tähän ongelmaan on välittää funktiolle viittaus kutsuvan ohjelman muuttujiin. Viittaus tehdään kirjoittamalla muuttujan nimen eteen &-merkki:

/* *********************************************************
VAIHDA.CPP
  Lukee arvot kahteen kokonaislukumuuttujaan, vaihtaa ne
  keskenään ja tulostaa muuttujien arvot.
********************************************************* */

#include <iostream.h>

/* Funktio vaihtaa parametrien arvot keskenään.
   Huomaa viittaukset parametreissa.            */
void vaihda(int &a, int &b)
{
  int apu;

  apu = a;
  a = b;
  b = apu;
}

int main(void)
{
  int eka, toka;

  cout << "\n\n";
  cout << "Anna kaksi kokonaislukua > ";
  cin >> eka >> toka;

  cout << "Luvut ennen vaihtoa:   " << eka << " " << toka << endl;
  vaihda(eka, toka);
  cout << "Luvut vaihdon jälkeen: " << eka << " " << toka << endl;

  return 0;
}

Kokeillaan uudestaan:

Anna kaksi kokonaislukua > 12 67
Luvut ennen vaihtoa:   12 67
Luvut vaihdon jälkeen: 67 12

Nyt toimii! Selitys on, että viittauksella luotuja muuttujia a ja b voidaan käyttää aivan kuin ne olisivat pääohjelman muuttujia eka ja toka, mutta vain eri nimisiä. Yleisesti ottaen: kaikki, mitä viittaukselle tehdään, tapahtuu myös varsinaiselle viittauksen kohteelle.

Kun haluat, että johonkin parametriin tehdyt muutokset välittyvät myös kutsuvaan yksikköön, käytä viittausta ko. parametrin kohdalla, ts. kirjoita funktion määrittelyssä parametrin nimen eteen &-merkki.