Ero sivun ”C” versioiden välillä

Poistettu sisältö Lisätty sisältö
Tronic (keskustelu | muokkaukset)
Tronic (keskustelu | muokkaukset)
Rivi 358:
 
=== Moniulotteiset ===
 
Moniulotteiset taulukot ovat taulukoita, joita indeksoidaan useammalla kuin yhdellä muuttujalla, esim. taulukko[i][j][k] (kolmiulotteinen taulukko). Niitä on C:ssä kahta päätyyppiä: staattisia ja dynaamisia, joista jälkimmäisiä kutsutaan myös pointteritaulukoiksi, koska ne on toteutettu pointterein.
 
[[Kuva:Array3x4.svg|3x4-kokoinen kaksiulotteinen taulukko, lukuarvoilla täytettynä.]]
 
Moniulotteiset taulukot ovat taulukoita, joita indeksoidaan useammalla kuin yhdellä muuttujalla, esim. taulukko<tt>int array[i][j][k]</tt> (kolmiulotteinen taulukko, jonka nimi on <tt>array</tt>, sisällön tyyppi <tt>int</tt>). Niitä on C:ssä kahta päätyyppiä: <strong>staattisia</strong> ja <strong>dynaamisia</strong>, joista jälkimmäisiä kutsutaan myös <strong>pointteritaulukoiksi</strong>, koska ne on toteutettu pointterein.
==== Staattiset ====
 
==== Staattiset moniulotteiset taulukot ====
Staattisessa kaksiulotteisessa taulukossa <tt>taulukko[3][4]</tt> on 12 alkiota, jotka on sisäisesti tallennettu 12-alkioiseen 1-ulotteiseen taulukkoon, mutta kääntäjä antaa indeksoida taulukkoa ikään kuin se olisi kaksiulotteinen. Kirjoittaessasi taulukko[i][j], hakee kääntäjä taulukostaan alkion [i * 4 + j]. Huomaa, että tässä kääntäjän oli tiedettävä taulukon taulukon koko toisen dimension suhteen. Vastaavasti kolmiulotteisella staattisella taulukolla taulukko[3][4][5], viitattaessa soluun taulukko[i][j][k], indeksi lasketaan [i * 4 * 5 + j * 5 + k]. Huomionarvoista tässä on, että taulukon käyttämiseksi kääntäjän täytyy aina tietää sen dimensiot, ensimmäistä lukuun ottamatta.
 
Staattisessa kaksiulotteisessa taulukossa <tt>taulukkoarray[3][4]</tt> on 12 alkiota, jotka on sisäisesti tallennettu 12-alkioiseen 1-ulotteiseen taulukkoon, mutta kääntäjä antaa indeksoida taulukkoa ikään kuin se olisi kaksiulotteinen. Kirjoittaessasi taulukko<tt>array[i][j]</tt>, hakee kääntäjä taulukostaan alkion <tt>[i * 4 + j]</tt>. Huomaa, että tässä kääntäjän oli tiedettävä taulukon taulukon koko toisen dimension suhteen. Vastaavasti kolmiulotteisella staattisella taulukolla <tt>taulukko[3][4][5]</tt>, viitattaessa soluun <tt>taulukko[i][j][k]</tt>, indeksi lasketaan <tt>[i * 4 * 5 + j * 5 + k]</tt> ja niin edelleen. Huomionarvoista tässä on, että taulukon käyttämiseksi kääntäjän täytyy aina tietää sen kaikki dimensiot, ensimmäistä lukuun ottamatta.
Staattiset moniulotteiset taulukot esitellään samoin kuin yksiulotteisetkin ja ne voi myös alustaa vastaavasti (jos ei alusta, ovat taulukon sisältämät arvot satunnaisia).
 
Staattiset moniulotteiset taulukot esitellään samoin kuin yksiulotteisetkin ja ne voi myös alustaa vastaavasti (jos ei alusta, ovat taulukon sisältämät arvot satunnaisia). Taulukkoa ei kuitenkaan yksiulotteisten tapaan voi helposti välittää funktiolle, koska funktion määrittelyssä tulee taulukon koon (paitsi ensimmäisen indeksin) olla määritelty jo lähdekoodissa, kuten tässä:
int taulukko[3][4] = { { 11, 12, 13, 14 }, { 21, 22, 23, 24 }, { 31, 32, 33, 34 } };
 
Taulukkoa ei voi helposti välittää funktiolle, koska funktion määrittelyssä tulee taulukon koon (paitsi ensimmäisen indeksin) olla määritelty jo lähdekoodissa:
 
#include <stdio.h>
Rivi 387 ⟶ 383:
}
 
Käytännössä moniulotteista staattista taulukkoa ei kannata koskaan välittää muualle. Jos tarvetta taulukon välittämiseen on, ovat yksiulotteiset taulukot (joita voi kertolaskun avulla käyttää moniulotteisena) ja dynaamiset taulukot parempia vaihtoehtoja.
==== Dynaamiset ====
 
==== Dynaamiset moniulotteiset taulukot ====
 
Pointteritaulukko on huomattavasti staattista taulukkoa joustavampi ratkaisu, mutta myös merkittävästi hankalampi luoda. Taulukko ei myöskään tuhoudu automaattisesti lohkon päätteeksi, vaan se täytyy itse vapauttaa. Staattisesta moniulotteisesta taulukosta poiketen, pointteritaulukko voidaan helposti välittää funktion argumenttina, tietämättä sen kokoa ennalta. Seuraavassa esimerkki täysin dynaamisesta moniulotteisesta taulukosta:
Rivi 430 ⟶ 428:
}
Edellä olevassa esimerkkikoodissa mallocin paluuarvoja ei tarkistettu, mutta oikeassa koodissa pitää aina mallocin kutsumisen jälkeen tarkistaa palauttiko kutsu <tt>NULL</tt>:n ja tällöin suorittaa vaadittavat siivoustoimenpiteet (esim. jo varatun muistin vapautus) ennen funktiosta poistumista.
 
Täysin dynaamisessa pointteritaulukossa rivien ei tarvitse olla yhtä pitkiä, eli loopin sisällä oltaisiin voitu tehdä <tt>malloc((i + 1) * sizeof(int))</tt>, jolloin ensimmäisellä rivillä olisi yksi alkio, toisella kaksi, jne. Rivien kokoa voi muuttaa (<tt>realloc</tt>) ilman että muulle taulukossa olevalle tiedolle tarvitsee tehdä mitään ja myös rivien lisäys ja poisto hoituu kevyesti rivipointtereita siirtelemällä (sisällä olevaa tietoa ei tarvitse siirtää esim. lisättäessä uusi rivi taulukon alkuun).
 
Monesti kuitenkin riittää myös kevyempi "puolidynaaminen" pointteritaulukko, jossa tieto on tallennettu isoon yksiulotteiseen taulukkoon (voi olla esim. staattinen moniulotteinen taulukko), mutta sitä indeksoidaan pointteritaulukon avulla. Seuraavassa esimerkki sellaisen luomisesta:
Rivi 441 ⟶ 439:
print(array, 3, 4);
 
Taulukko <tt>static_array</tt> olisi yhtä hyvin voinut olla staattinen kaksiulotteinen taulukko, koska sellaisen sisäinen rakenne on identtinen yksiulotteisen taulukon kanssa. Pointteritaulukko taasen on tällä kertaa toteutettu pinosta varattuna, eikä mallocilla varattuna, joten sitä ei tarvitse erikseen vapauttaa funktion päättyessä. Kuitenkin taulukko voidaan <tt>print</tt>-funktiolle välittää samoin kuin mikä tahansa pointteritaulukko (huomaa implisiittinen tyyppimuunnos <tt>int* array[3]</tt>:sta <tt>int**</tt>:ksi funktiokutsun yhteydessä).
 
== Merkkijonot ==
Noudettu kohteesta ”https://fi.wikibooks.org/wiki/C