Taulukot¶
Kurssilla on totuttu käyttämään STL:n vector
-rakennetta
tilanteissa, joissa keskenään saman tyyppisiä arvoja halutaan
tallentaa siten, että alkioihin päästään käsiksi järjestysnumerolla
(indeksillä). C++:ssa on kuitenkin myös alkeellisempi tyyppi, joka
käyttäytyy osittain samoin vektorin kanssa. Tätä rakennetta kutsutaan
taulukoksi (array).
Taulukko on hyvin yksinkertainen, kooltaan staattinen tietorakenne
(alkioiden lukumäärä on kiinteä), jonka yksitäisiin alkioihin päästään
käsiksi []
-operaattorilla.
Rakenne on suoraa perintöä C-kielestä, joka on C++:n esi-isä.
Tällä kurssilla taulukoille ei itsessään ole käyttöä, koska kaikki
tarvittavat asiat voidaan tehdä helpommin vector
:in avulla, mutta
yleissivistävistä syistä on hyvä tietää jotain taulukon luonteesta.
Tätä tietoa tarvitaan, jos ikinä tulee eteen tarve kirjoittaa ohjelmia
C-kielellä.
Taulukkotyyppinen muuttuja määritellään seuraavasti:
int luvut[3]; // Taulukossa tilaa kolmelle int:ille.
Edellisen määrittelyn seurauksena kääntäjä varaa niin pitkän yhtenäisen pätkän
muistia, että sinne voidaan sijoittaa peräkkäin kolme
int
-tyyppistä arvoa:
Taulukon alkioita voidaan nyt käsitellä []
-operaattorilla:
luvut[0] = 6;
luvut[1] = 12;
luvut[2] = 24;
cout << luvut[0] + luvut[2] << endl; // 30
minkä jälkeen tilanne muistissa näyttäisi seuraavalta:
Taulukkotyyppi on toteutettu tehokkuussyistä siten, että taulukko esitetään toteutustasolla vakio-osoittimena sen ensimmäiseen alkioon. Eli siis koodi
cout << luvut << endl;
tulostaisi esimerkkitaulukosta näytölle osoitteen 0x000004
.
Seurauksena siitä, että taulukko samaistetaan aina osoitteeksi sen ensimmäiseen alkioon, on taulukko melko alkeellinen tietotyyppi:
- Taulukkomuuttujaa ei voi sijoittaa toiseen taulukkomuuttujan
operaattorin
=
avulla. Taulukkoa ei myöskään voi alustaa toisella taulukolla. - Jos taulukko annetaan funktiolle parametrina, käyttäytyy se aina
viiteparametrin tavoin, koska funktio saa muodollisessa parametrissa
tiedon taulukon ensimmäisen alkion muistiosoitteesta. Kun tätä
osoitetta sitten käsitellään
[]
-operaattorilla, päädytään luonnollisesti operoimaan alkuperäisen taulukon alkioilla. - Taulukko ei voi olla suoraan STL-säiliöiden alkiona.
Taulukko voidaan kuitenkin käydä läpi osoittimen avulla:
int* taulukko_osoitin = nullptr;
taulukko_osoitin = luvut;
while ( taulukko_osoitin < luvut + 3 ) {
cout << *taulukko_osoitin << endl;
++taulukko_osoitin;
}
Edellä on hyödynnetty nk. osoitinaritmetiikkaa: Taulukon alkuosoitteeseen voidaan lisätä kokonaisluku, jolloin tuloksena saadaan osoitin alkioon, jonka indeksi vastaa lisättyä kokonaislukua.
Jos lisätty luku on taulukon alkioiden lukumäärä, saadaan osoitin siihen kohtaan muistissa, joka on heti viimeisen alkion perässä:
cout << luvut + 3 << endl; // Tulostuu muistiosoite 16
Tätä osoitetta voidaan käyttää näppärästi taulukkoa osoittimen avulla läpi käyvän silmukan ehdossa, kuten edellä oli tehty.
Käytännössä osoitinaritmetiikasta seuraa myös se, että esimerkiksi koodi
cout << luvut[2] << endl;
luvut[1] = 99;
tarkoittaa samaa kuin koodi
cout << *(luvut + 2) << endl;
*(luvut + 1) = 99;
Kuten todettua, tällä kurssilla taulukot ja niiden käyttäytyminen ei aivan olennaisinta sisältöä. Asia kannattaa kuitenkin tiedostaa yleissivistävistä syistä. Ei ole aivan odottamatonta, että esimerkiksi myöhemmillä kursseilla (Mikroprosessorit, Laitteistonläheinen ohjelmointi, tms.) saattaa päätyä kirjoittamaan matalamman tason koodia C-kielellä, jossa asia tulee vastaan.