Helsingin yliopisto Tietojenkäsittelytieteen laitos
 

Tietojenkäsittelytieteen laitos

Tietoa laitoksesta:

 
Helsingin yliopisto / Tietojenkäsittelytieteen laitos / Copyright © 2000 Jan Lindström. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

58127-1 C-ohjelmointi : 4 Taulukot


  • 4 Taulukot

    4 Taulukot

    Muuttujien määrittelyssä voi olla muuttujan tunnuksen perässä hakasuluissa oleva vakio, joka ilmoittaa, että muuttuja on taulukko. Vakio ilmoittaa kuinka monta alkiota taulukossa on. Taulukko koostuu keskenään samantyyppisistä tietoalkioista, jotka sijaitsevat muistissa peräkkäin ja joiden lukumäärä on siis kiinteä. Taulukon alkioihin voidaan viitata indeksoiduilla muuttujilla kuten ohjelmointikielissä ylleensä. Indeksi kirjoitetaan hakasulkuihin. C-kielessä taulukon indeksin alaraja on aina nolla. Tästä seuraa, että

    • Indeksin yläraja on yhtä pienempi kuin alkioiden määrä

    • Indeksoitu muuttuja a[i] ei viitaan a:n i:nteen vaan i+1:nteen alkioon.

    • Huomaa, että C-kielessä ei tarkisteta taulukon rajoja, joten indeksointi taulukon ulkopuolelle on mahdollista (mutta aiheuttaa virheitä).

    float vektori[9];
    int numeroita[];
    
    Taulukkomuuttuja voidaan määrittelynsä yhteydessä alustaa. Tämä tehdään kirjoittamalla taulukon nimen perään yhtäläisyysmerkki ja aaltosulkuihin taulukon alkioiden arvot, jotka ilmoitetaan vakiolausekkeilla ja erotetaan toisistaan pilkuilla. Jos aaltosuluissa on vähemmän arvoja, kuin taulukossa on alkioita, taulukon ylimääräiset (loppupään) komponentit saavat arvokseen nollan.

    Jos halutaan aluksi nollata taulukko, niin riittää siis käyttää alustusmerkintää = {0}. Esimerkiksi:

    float p[4] = { 0.2, 0.3, 0.3, 0.2 };
    int x[10] = {1, 3, 5};
    float a[1999] = {0.0};
    
    Jos taulukon alkiot itsessään ovat taulukoita, se voidaan alustaa kirjoittamalla taulukon kunkin alkion omat alkiot aaltosulkuihin. Esimerkiksi:

    int taulukko[3][3] = { { 1, 0, 0 },
                           { 0, 1, 0 },
                           { 0, 0, 1 } 
                         };
    
    Tämäntapaisissa initialisoinnessa voidaan muut aaltosulut kuin uloimmat jättää pois, jos initialisointi sisältää täyden määrän alkioita. Jos taas em. alustus tehtäisiin seuraavasti, ei sulkuja voisi jättää pois:

    int taulukko[3][3] = { { 1 },
                           { 0, 1    },
                           { 0, 0, 1 } 
                         };
    
    Taulukon määrittelyssä voidaan eräissä tapauksissa jättää ilmoittamatta taulukon koko. Sallitut tilanteet ovat seuraavat:
    • Taulukon määrittelyssä on initialisointi.
    • Taulukko on funktion muodollinen argumentti.
    • Kyseessä on globaalin taulukon esittely.

    4.1 Taulukot argumentteina

    Funktion argumentti voidaan määritellä taulukoksi. Tällöin argumenttimäärittely on muodoltaan samanlainen kuin taulukkomuuttujan määrittely, kuitenkin niin, että taulukon koon voi jättää ilmoittamatta. Esimerkiksi seuraavassa funktion otsikossa määritellään funktion f argumentti s taulukoksi:

    void f(int s[])
    
    Taulukoiden välittäminen argumentteina on kuitenkin näennäistä, sillä argumenttina oleva taulukko on itse asiassa osoitin. Jos argumenttina on taulukko, jonka alkioiden tyyppi on t, kääntäjä käsittelee sen aivan samoin kuin osoittimen tyyppiä t oleviin objekteihin. Vastaava todellisen argumentin tulee olla samantyyppinen osoitin, ja funktiolle välittyy pelkkä osoite - mitään taulukon kopioimista ei C-kielen argumenttivälityksessä koskaan tapahdu. Todellinen argumentti voi olla taulukon nimi, koska sehän edustaa lausekkeessa esiintyessään osoitinta taulukon ensimmäiseen alkioon. Todellinen argumentti voi olla myös osoitin jonkin taulukon muuhunkin alkioon kuin ensimmäiseen, esim. muotoa &a[i]. Tätä piirrettä, jolla on vastine FORTRAN-kielessä, käytetään usein siihen, että funktiolla käsitellään osa taulukosta.


    4.2 Moniulotteiset taulukot

    C-kielessä taulukolla on yksi indeksi. Koska kuitenkin taulukon alkiona voi olla taulukko, voidaan taulukko käytännössä määritellä moniuloitteiseksi eli sellaiseksi, jolla on monta indeksiä, esimerkiksi:

    float a[2][3];
    int kuutio[3][10][4];
    
    Hakasuluissa olevat luvut (tai vakiolausekkeet) osoittavat kunkin indeksin mahdollisten arvojen lukumäärän. Indeksin alaraja on aina nolla. Moniulotteista taulukkoa indeksoidaan luonnollisesti yhtä monella indeksillä kuin määrittelyssä on indeksejä, esim a[i][j]. Jos indeksejä on vähemmän, rakenne tarkoittaa taulukon alkiona olevaa taulukkoa, esim a[j] matriisin vaakarivinä olevaa taulukkoa; taulukko puolestaan lausekkeessa esiintyessään muuttuu taulukon alun osoitteeksi.

    Koska moniulotteinen taulukko on periaatteellisesti yksiulotteinen taulukko, jonka alkiot ovat taulukoita, niin moniulotteinen taulukko sijaitsee muistissa vakariveittäin. Moniulotteisen taulukon dimensioinnille tai vastaaville indeksoiduille muuttujille ei C-kielessä ole mitään lyhennysmerkintää (esimerkiksi a[i,j]). Asian tekee hankalaksi se, että C-kielessä ilmaisu a[i,j] on sinänsä laillinen, mutta hakasulkujen sisällä on pilkkuoperaattorilla muodostettu yksi lauseke (jonka arvo on j:n arvo), joten rakenne tarkoittaa aivan muta kuin muihin kieliin tottunut äkkiseltään luulisi.

    Moniulotteisen taulukon määrittelyssä saa vain ensimmäisen indeksin arvojen lukumäärä puuttua. Tämä johtuu siitä, että muutoin kääntäjä ei pystyisi tuottamaan koodia taulukon indeksointia varten. Indeksointihan edellyttää alkioiden koon tuntemista. Esimerkiksi:

    #define MAXKOKO 5
    void matriisit_yhteenlaske(double a[][MAXKOKO],b[][MAXKOKO], double c[][MAXKOKO],int m)
    {
        int i,j;
    
        for(i = 0, i < m; i++)
        {
            for( j = 0; j < MAXKOKO; j++)
            {
                c[i][j] = a[i][j] + b[i][j];
            }
        }
    }
    


    Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)