2.8.5 Taulukot funktion parametrina

Funktion parametreina taulukot käyttäytyvät kuten tavalliset muuttujat paitsi, että

Huomaa, että taulukko ei käy funktion paluuarvoksi!

Seuraava ohjelma laskee ns. Fibonaccin luvut ja sijoittaa luvut taulukkoon. Fibonaccin luvut ovat kokonaislukuja, joista ensimmäiset ovat 0 ja 1 ja kaikki muut saadaan laskemalla kaksi edellistä lukua yhteen. Näin saadaan lukusarja 0, 1, 1, 2, 3, 5, 8, 13, ... Lukujen laskeminen ja niiden tulostaminen suoritetaan omissa aliohjelmissaan, jotta nähdään, miten taulukkoa käytetään parametrina.

/* *********************************************************
FIBO.CPP
  Laskee taulukkoon Fibonaccin luvut.
********************************************************* */

#include <iostream.h>

#define N 10 // laskettavien lukujen lukumäärä

void esittele(int n)
{
  cout << "\n\n";
  cout << "Lasketaan " << n << " ensimmäistä Fibonaccin lukua." << endl;
}

/* Laskee n kpl Fibonaccin lukuja ja sijoittaa ne taulukkoon.
   Huomaa, että parametrina olevan taulukon kokoa ei tarvitse
   ilmoittaa; käsiteltävien alkioiden lukumäärä on kuitenkin omana
   parametrinaan. Huomaa myös, että viittausta & ei käytetä vaikka
   funktio muuttaakin taulukon arvoa.                              */
void laske_fibo(int taulu[], int n)
{
  int i;
  taulu[0] = 0;                         // 1. luku
  taulu[1] = 1;                         // 2. luku
  for (i=2; i<n; i++)                   // luvut 3...n
    taulu[i] = taulu[i-1] + taulu[i-2];
}

/* Tulostaa taulukon luvut. */
void tulosta(int taulukko[], int koko)
{
  int i;
  for (i=0; i<koko; i++)
    cout << "  " << taulukko[i];
  cout << endl;
}

int main(void)
{
  int taulu[N]; // tästä taulukon kokoa ei saa jättää pois!

  esittele(N);
  laske_fibo(taulu, N);  // funktioiden kutsuissa pelkkä taulukon
  cout << "Luvut ovat:"; //  nimi, ei hakasulkuja eikä kokoa
  tulosta(taulu, N);

  return 0;
}

Edellä funktiot laske_fibo ja tulosta on tehty yleiskäyttöisiksi siinä mielessä, että niillä voidaan käsitellä kaiken kokoisia taulukoita (kunhan ei ylitetä taulukon määrittelyssä annettua maksimikokoa N).

Edellisessä ohjelmassa on pieni vaaran paikka. Jos ohjelman vakiomäärittelyssä määritellään #define N 1 niin aliohjelmassa laske_fibo tehdään jotakin hyvin laitonta, josta kääntäjä kuitenkaan ei millään tavalla varoita. Mitä?

Tee ohjelma, jossa tallennetaan viikon jokaisen päivän lämpötilat. Tallenna lämpötilat taulukkoon.

Seuraava esimerkkiohjelma järjestää kokonaislukutaulukon alkiot suuruusjärjestykseen, pienimmästä suurimpaan. Lajittelualgoritmina käytetään ns. kuplalajittelua, jonka idea on hyvin yksinkertainen: Ensin siirretään taulukon "painavin" (eli tässä tapauksessa suurin) alkio viimeiseksi. Sen jälkeen tuo viimeinen paikka voidaan unohtaa, ja tutkitaan vain jäljelle jäänyttä (yhtä paikkaa lyhyempää) osataulukkoa. Siirretään tämän osataulukon painavin alkio sen viimeiseen paikkaan, ja tutkitaan sitten jäljelle jäänyttä (taas yhtä paikkaa lyhyempää) osataulukko. Näin jatketaan kunnes jäljellä on vain kahden alkion pituinen taulukko, jonka käsittelyn jälkeen kaikki alkiot ovat oikeilla paikoillaan, painavin pohjalla (viimeisenä) ja kevyin pinnalla (ensimmäisenä) .

/* *********************************************************
KUPLA.CPP
  Järjestää taulukon kuplalajittelulla.
********************************************************* */

#include <iostream.h>

#define KOKO 10

/* Alkioiden vertailufunktio. Palauttaa
   -1, jos a:n pitäisi olla ennen b:tä,
    0, jos a ja b ovat samanarvoiset,
   +1, jos a:n pitäisi olla b:n jälkeen. */
int vertaa(int a, int b)
{
  return (a - b);
}

/* Alkioiden vaihtofunktio. */
void vaihda(int &a, int &b)
{
  int apu;

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

/* Siirtää taulukon "painavimman" alkion viimeiseen paikkaan. */
void siirra_painavin(int taulukko[], int koko)
{
  int i, vertailu;

  /* käydään läpi koko taulukko ja verrataan peräkkäisiä alkioita */
  for (i=0; i<koko-1; i++) {
    /* alkion i pitäisi olla ennen alkiota i+1;
       jos väärässä järjestyksessä, vaihdetaan */
    vertailu = vertaa(taulukko[i], taulukko[i+1]);
    if (vertailu > 0)
      vaihda(taulukko[i], taulukko[i+1]);
  }
  /* nyt kaikkein painavin alkio on paikassa koko-1 */
}

/* Kuplalajittelu kokonaislukutaulukolle. */
void jarjesta(int taulukko[], int koko)
{
  int pituus; // taulukon käsiteltävän osan pituus

  /* taulukon käsiteltävä osa lyhenee yhdellä joka kierroksella */
  for (pituus=koko; pituus>1; pituus--)
    siirra_painavin(taulukko, pituus); // käsitellään osataulukko
}

void tulosta(int taulukko[], int koko)
{
  int i;

  for (i=0; i<koko; i++)
    cout << "  " << taulukko[i];
  cout << endl;
}

int main(void)
{
  int taulu[KOKO] = {4, 7, 1, 9, 3, 0, 2, 5, 8, 6};

  cout << "Alkuperäinen:";
  tulosta(taulu, KOKO);

  jarjesta(taulu, KOKO);

  cout << "Järjestetty :";
  tulosta(taulu, KOKO);

  return 0;
}

Miten edellistä ohjelmaa pitäisi muuttaa, jos haluttaisiinkin lajitella liukulukutaulukko? Entä, jos luvut haluttaisiin järjestää päinvastaiseen järjestykseen, suuremmasta pienempään?