Taulukot C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa. Taulukon muuttujilla (muistipaikoilla) on yhteinen nimi. Jokaiseen yksittäiseen muistipaikkaan liittyy kokonaisluku indeksi, joka ilmoittaa yksittäisen muistipaikan sijainnin taulukossa. Taulukon ensimmäisen muistipaikan indeksi on 0 (nolla) ja viimeisen paikan indeksi on taulukon koko -1. C-kielessä taulukot ja osoittimet liittyvät läheisesti toisiinsa, taulukon nimi viittaa taulukon ensimmäiseen muistipaikkaan. 310
Yksiulotteinen taulukko Yksiulotteisen taulukon yleinen muoto: tietotyyppi taulukonnimi [ taulukonkoko ]; Tietotyyppi määrittää taulukon alkioiden tietotyypin ja taulukonkoko määrittää kuinka monta alkiota taulukko sisältää ja taulukonnimi on ohjelmoijan antama tunniste (nimi). Esimerkiksi kokonaislukuja tallettavan taulukon määrittely. int lukuja [10]; /* varataan tilaa 10 kokonaisluvulle */ 311
Taulukon yksittäiseen alkioon viitataan indeksin avulla, indeksin arvo on kokonaisluku 0... taulukonkoko -1. Indeksin arvo kirjoitetaan hakasulkeisiin taulukon nimen perään: int paikka = 8; lukuja[0] = 56; /* tallettaa kokonaisluvun 56 taulukon 1. paikkaan */ lukuja[5] = -100; /* tallettaa luvun 100 taulukon 6. paikkaan */ lukuja[paikka] = lukuja[0] + 99; 312
indeksit lukuja[0] = 56; lukuja[5] = -100; 0 56 1 2 3 4 5-100 6 7 8 155 9 lukuja taulukon nimi lukuja[paikka]= lukuja[0]+99; 8 paikka 313
Taulukko voidaan alustaa käyttämällä ns. alustuslistaa. double saatila[ 5 ] = {0.0, 5.1, -10.5, -45.5, 21.0 ; Taulukko saatila täytetään siten että saatila [0] saa arvon 0.0, saatila [1] saa arvon 5.1 jne. Jos alustuslista on lyhyempi kuin taulukon koko, täytetään jäljelle jäävät paikat nollilla. int arvoja [100] = { 0 ; /* täyttää taulukon nollilla */ 314
Jos taulukolle ei anneta määrittelyssä kokoa, mutta taulukko alustetaan alustuslistan avulla, varataan taulukolle tilaa juuri niin paljon, että kaikki alustuslistan tiedot mahtuvat taulukkoon. int arvosanoja [] = {1, 2, 3, 4, 5 ; Yo. määrittelyssä tilaa varataan viidelle kokonaisluvulle. Merkkitaulukon yhteydessä on mahdollista seuraava: char merkit [] = "abc"; joka vastaa samaa kuin: char merkit [] = { 'a', 'b', 'c','\0'; 315
Toistorakenteet ja taulukot Taulukkojen käsittely helpottuu, kun käytetään toistorakenteita. Esimerkki: Täytetään taulukko ja tulostetaan taulukon sisältö for - toistorakennetta hyödyntäen. 316
#include <stdio.h> int main(void){ int i; /* laskuri ja taulukon ideksi */ int taulukko[10]; /* tilaa 10 kokonaisluvulle */ /* täytetään taulukko alkaen paikasta 0 käyttäjän syöttämillä kokonaisluvuilla */ /* käytetään for-toistorakennetta */ for(i=0; i < 10; i++) { printf("\nanna %d. kokonaisluku > ", (i+1)); scanf("%d", &taulukko[i]); 317
/* tulostetaan taulukon sisältö */ printf("\ntaulukon sisältö\n"); for(i=0; i < 10; i++){ printf("%d ", taulukko[i]); printf("\n\n"); return(0); 318
319
Edellinen ohjelma toteutettuna while-rakenteella: #include <stdio.h> int main(void){ int i; /* laskuri ja taulukon ideksi */ int taulukko[10]; /* tilaa 10 kokonaisluvulle */ /* täytetään taulukko alkaen paikasta 0 käyttäjän syöttämillä kokonaisluvuilla */ /* käytetään while-toistorakennetta */ i=0; /* alustus */ while(i < 10) { printf("\nanna %d. kokonaisluku > ", (i+1)); scanf("%d", &taulukko[i]); i++; /* seuraava paikka */ 320
/* tulostetaan taulukon sisältö */ printf("\ntaulukon sisältö\n"); i=0; while(i < 10){ printf("%d ", taulukko[i]); i++; printf("\n\n"); return(0); 321
C-kielessä ei tehdä mitään taulukoiden rajojen tarkastuksia, jos indeksi viittaa taulukon ulkopuolelle ja viittaukset kohdistuvat joidenkin muiden muuttujien muistialueelle. Tilanteesta riippuen ohjelma saattaa toimia joten kuten tai sitten sen suoritus keskeytyy muistivirheeseen (tämä riippuu käyttöjärjestelmästä). Esimerkkiohjelma, jossa viitataan taulukon ulkopuolelle: 322
#include <stdio.h> int main ( void ) { int i; /* laskurimuuttuja */ int pois; int x[5] = {12345; /* viiden merkin taulukko */ for ( i = 0; i < 1000; i++) { printf("%d", x[i]); return (0); 323
Mac Os X-ympäristössä ohjelman suoritus näyttäisi tältä: Segmentation fault Windows XP-ympäristössä ohjelman suoritus tuottaisi alla olevan kaltaisen tuloksen (vain osa tulostuksesta): 12345000051245120419914711334264133073642394004239404423940800236764821473484801 01245076-505882336124515241985544239388012451682011698375023676482147348480-2156 510881245128-2142026492-12011777033201176321600041990040202089350532116121240320 20135217210000020003564000760826203756508086921621402117213281215001121168246971 54411321361044909000000000023652380115557017245111881517741254395755701724720906 57864403602942700001844001760826203584506366922100125428424453819482895042960407 21000000100000000688135774712037536751668478330147726881367655371077988953014771 79299397602291714352572745637340141760227364226336619244734007672746106619235753 67557471215747116968158437602281648816576678286619250222828536701362228278734007 66422645688138849152997929957727458066192433997806353897837356056422581340792634 07921648811666847716553649222832676022207340153399779777988187209065327685128836 18661925475367547274601399780634734423211310314577431457745439522753676166192522 09726166192046357094707800520972687274563760228678644211166881357747120375367516 68478330147726881367655371077988953014771655367152429857667820115100023873622129 74-15026995502960441410000001000138118800068813577471203753675166847833014772688 13676553710779889530147716553671524298576678202883699747121664881757536741727461... 324
C-kielestä on jätetty virhetarkastukset pois tehokkuussyistä ja vastuu on ohjelman kirjoittajalla! 325
Moniulotteiset taulukot C-kielessä moniulotteiset taulukot määritellään kirjoittamalla yhtä monet sulut kuin taulukossa on dimensioita. Esimerkiksi kaksiulotteisen taulukon määrittely: int matriisi [10][10]; /* varataan tilaa 100:lle kokonaisluvuille */ Moniulotteinen taulukko voidaan myös alustaa alustuslistan avulla int matriisi [4][4] = { {1, 2, 3, 4, {5, 6, 7, 8, {9, 0, 1, 2, {3, 4, 5, 6 ; 326
rivi-ineksit sarakkeet 0 1 2 3 sarakeindeksi rivit 0 1 2 3 4 2 5 6 7 8 3 9 0 1 2 3 3 4 5 6 matriisi[3][1] 327
#include <stdio.h> int main(void) { int i, j; /* rivi- ja sarakeindksit */ int matriisi [4][4] = { {1, 2, 3, 4,{5, 6, 7, 8, {9, 0, 1, 2, {3, 4, 5, 6 ; printf("\nkaksiulotteisen taulukon sisältö:\n"); for(i=0; i < 4; i++){ for(j=0; j < 4; j++){ printf("%d ", matriisi[i][j]); printf("\n"); printf("\n\n"); return(0); 328
329
Taulukot funktion parametrina C-kielessä taulukko välitetään funktiolle osoittimen avulla. Funktiolle välitetään kopio taulukon alkuosoitteesta, taulukon elementtien sisältöä ei kopioida (tehokkuus!). Esimerkkiohjelma, joka palauttaa reaalilukutaulukon alkioiden summan. 330
/* Funktio laskesumma saa parametrinaan reaalilukutaulukon alkuosoitteen ja taulukon koon (n). Se palauttaa taulukon alkioiden summan. */ double laskesumma(double luvut[], int n) { int i; double yhteensa = 0.0; for ( i = 0; i < n; i++) { yhteensa = yhteensa + luvut[i]; return ( yhteensa ); 331
Funktion kutsussa taulukon nimi (luvut) kirjoitetaan todellisena parametrina ilman sulkeita. #include <stdio.h> double laskesumma(double luvut[], int n); int main( void ){ double luvut [5] = {1.2, 3.0, 5.6, 9.9, 100.9; double tulos; int lukumaara = 5; tulos = laskesumma ( luvut, lukumaara ); printf("\ntaulukon alkioiden summa on: %.2lf\n", tulos); return 0; 332
Jos halutaan estää funktiota muuttamasta parametrinaan saamaansa taulukkoa, käytetään funktion määrittelyssä lisämäärettä const, jolloin taulukon sisältöä voidaan lukea mutta ei muuttaa (kääntäjä tarkastaa ). Taulukon yksittäisen elementin välittäminen funktiolle tapahtuu välittämällä kopio kyseisen elementin arvosta kutsuttavalle funktiolle. 333
C-kielessä funktion palautusarvon tyyppinä ei voi olla taulukko. Jos funktion pitäisi palauttaa taulukko, joka sisältää kahden parametrina saamansa taulukon vastaavien solujen summan. Ratkaisuna on välittää myös täytettävä taulukko kutsuvasta ohjelmasta. void addarray(const double ar1[], const double ar2[], double arsum [], int n){ int i; for ( i = 0; i < n; i++) { arsum[i] = ar1[i] + ar2[i]; 334
Moniulotteinen taulukko funktion parametrina #include <stdio.h> #define SARAKKEET 4 void tulostataulukko(int taulukko[][sarakkeet], int n); int main(void) { int i, j; /* rivi- ja sarakeindksit */ int matriisi [4][SARAKKEET] = { {1, 2, 3, 4,{5, 6, 7, 8, {9, 0, 1, 2,{3, 4, 5, 6 ; tulostataulukko(matriisi, 4); return(0); 335
void tulostataulukko(int taulukko[][sarakkeet], int rivit){ int i, j; /* rivi- ja sarakeindksit */ printf("\nkaksiulotteisen taulukon sisältö:\n"); for(i=0; i < rivit; i++){ for(j=0; j < SARAKKEET; j++){ printf("%d ", taulukko[i][j]); printf("\n"); 336
Jos funktio saa parametrina muun kuin yksiulotteisen taulukon on funktion esittelyssä ja määrittelyssä otsikkorivillä kerrottava taulukon muiden kuin ensimmäisen dimensioiden koot muodollisen parametrin nimen perässä olevissa hakasulkeissa void tulostataulukko(int taulukko[][sarakkeet], int rivit) Yllä olevassa esimerkissä taulukko on kaksiulotteinen taulukko, [SARAKKEET] ilmaisee kääntäjälle toisen ulottuvuuden koon. Tässä oletetaan että SARAKKEET on määritelty #define direktiivillä. Taulukon rivien lukumäärä ilmaistaan parametrilla rivit. 337
Jos taulukon sarakkeiden koko ei ole määritelty #define direktiivillä on funktiolle välitettävä vielä erikseen sarakkeidenkin määrä parametrina, jotta taulukkoa voidaan käsitellä oikein. void tulostataulukko(int taulukko[][256], int rivit, int sarakkeet ) 338
Funktion toteutus näyttäisi tältä: void tulostataulukko(int taulukko[][256], int rivit, int sarakkeet){ int i, j; /* rivi- ja sarakeindksit */ printf("\nkaksiulotteisen taulukon sisältö:\n"); for(i=0; i < rivit; i++){ for(j=0; j < sarakkeet; j++){ printf("%d ", taulukko[i][j]); printf("\n"); 339
Funktiota kutsuttaisiin: tulostataulukko(matriisi, 4, 4); 340