Dynamic array/fi: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Dynamic array/fi
| Old | New | Line | |
|---|---|---|---|
| 1 | + | # Dynaaminen taulukko | |
| 2 | + | ||
| 3 | + | Dynaaminen taulukko on [[Array/fi|taulukko]], jonka mittoja ei tunneta käännösaikana. Dynaaminen taulukko-tyyppi ei ole ainoa sellainen tyyppi, joka tarjoaa vaihtelevan pituisen taulukon, mutta (vuonna 2018) se on ainoa mitä [[FPC|Free Pascal]]-tukee. | |
| 4 | + | ||
| 5 | + | ## Käyttö | |
| 6 | + | ||
| 7 | + | ### Käsite | |
| 8 | + | ||
| 9 | + | Dynaaminen taulukon määritys varaa tilaa vain [[Pointer|osoittimelle]]. [[runtime|Ajon aikana]] eri rutiinit varmistavat sen kätevän käytön, mutta tärkeintä on, että [[Compiler/fi|kääntäjä]] tukee matriisin elementtien pääsyä sijoittamalla indeksit hakasulkeisiin (toteutetaan osoittimen automaattisena viittauksena). | |
| 10 | + | ||
| 11 | + | Dynaamisen taulukon indeksit ovat aina ei-negatiivisia kokonaislukuja, jotka alkavat nollasta joka vastaa ensimmäistä elementtiä. Lueteltua tyyppiä, muuta ordinaalityyppiä ei voida käyttää indeksinä tai muuttaa ensimmäistä elementtiä, joka on määritetty indeksillä `1`. | |
| 12 | + | ||
| 13 | + | ## määritelmä | |
| 14 | + | ||
| 15 | + | Yksiulotteinen dynaaminen taulukko on määritellään seuraavasti: | |
| 16 | + | ||
| 17 | + | ``` pascal | |
| 18 | + | array of char | |
| 19 | + | ``` | |
| 20 | + | ||
| 21 | + | Huomaa, miten taulukon kokoa ei ole määritetty. | |
| 22 | + | ||
| 23 | + | Moniulotteisen taulukon määrittelemiseksi, perustyypiksi määritetään itse taulukko. | |
| 24 | + | ||
| 25 | + | ``` pascal | |
| 26 | + | array of array of longInt | |
| 27 | + | ``` | |
| 28 | + | ||
| 29 | + | ### Mitoitus | |
| 30 | + | ||
| 31 | + | Kääntäjän [[Procedure/fi|aliohjelma]] [`setLength`](https://www.freepascal.org/docs-html/rtl/system/setlength.html) muuttaa dynaamisen taulukon pituutta edellyttäen, että muistia on riittävästi. | |
| 32 | + | ||
| 33 | + | ``` pascal | |
| 34 | + | program setLengthDemo(input, output, stdErr); | |
| 35 | + | var | |
| 36 | + | sieve: array of longWord; | |
| 37 | + | begin | |
| 38 | + | setLength(sieve, 1337); | |
| 39 | + | end. | |
| 40 | + | ``` | |
| 41 | + | ||
| 42 | + | Aliohjelma varaa muistia annetun määrän mukaisesti kyseisen tyypin tietueelle ja myös joillekin hallintatiedoille. Sitten se [*kopioi*](https://www.freepascal.org/docs-html/rtl/system/copyarray.html) kaikki vanhan inkarnaation elementit uuteen. | |
| 43 | + | ||
| 44 | + | Myös moniulotteiset taulukot voidaan muuttaa `setLength` aliohjelmalla. | |
| 45 | + | ||
| 46 | + | ``` pascal | |
| 47 | + | program multidimensionalSetLengthDemo(input, output, stdErr); | |
| 48 | + | var | |
| 49 | + | samples: array of array of smallInt; | |
| 50 | + | begin | |
| 51 | + | setLength(samples, 12, 64); | |
| 52 | + | end. | |
| 53 | + | ``` | |
| 54 | + | ||
| 55 | + | Taulukon `samples` ensimmäisen ulottuvuuden todelliset indeksit ovat `0..11` kun taas toisen ulottuvuuden kelvolliset indeksit ovat alueella `0..63`. | |
| 56 | + | ||
| 57 | + | Yksi varsin hyödyllinen tosiasia on, että rajoituksen, jonka mukaan kaikkien ulottuvuuksien on oltava samankokoisia, ei sovelleta dynaamisiin taulukoihin. | |
| 58 | + | ||
| 59 | + | ``` pascal | |
| 60 | + | program binomialPotence(input, output, stdErr); | |
| 61 | + | var | |
| 62 | + | pascalsTriangle: array of array of longWord; | |
| 63 | + | exponent: longInt; | |
| 64 | + | factor: longInt; | |
| 65 | + | begin | |
| 66 | + | setLength(pascalsTriangle, 20); | |
| 67 | + | ||
| 68 | + | setLength(pascalsTriangle[0], 1); | |
| 69 | + | pascalsTriangle[0][0] := 1; | |
| 70 | + | ||
| 71 | + | setLength(pascalsTriangle[1], 2); | |
| 72 | + | pascalsTriangle[1][0] := 1; | |
| 73 | + | pascalsTriangle[1][1] := 1; | |
| 74 | + | ||
| 75 | + | // construct values by simple addition | |
| 76 | + | for exponent := 2 to high(pascalsTriangle) do | |
| 77 | + | begin | |
| 78 | + | setLength(pascalsTriangle[exponent], exponent + 1); | |
| 79 | + | pascalsTriangle[exponent][0] := 1; | |
| 80 | + | pascalsTriangle[exponent][exponent] := 1; | |
| 81 | + | for factor := 1 to exponent - 1 do | |
| 82 | + | begin | |
| 83 | + | pascalsTriangle[exponent][factor] := | |
| 84 | + | pascalsTriangle[exponent - 1][factor - 1] + | |
| 85 | + | pascalsTriangle[exponent - 1][factor]; | |
| 86 | + | end; | |
| 87 | + | end; | |
| 88 | + | ||
| 89 | + | // ... | |
| 90 | + | ``` | |
| 91 | + | ||
| 92 | + | ### Alustus | |
| 93 | + | ||
| 94 | + | FPC:n versiosta 3.0.0 lähtien dynaaminen taulukko, jotka eivät ole anonymous, varustetaan automaattisesti “constructor” (rakentajalla), koska se on tuttua olio-ohjelmoinnista. Tämän avulla voit yhdistää `setLength`-kutsu ja joukon toimeksiantoja yhteen lausekkeeseen: | |
| 95 | + | ||
| 96 | + | ``` pascal | |
| 97 | + | program dynamicArrayCreateDemo(input, output, stdErr); | |
| 98 | + | type | |
| 99 | + | truths = array of boolean; | |
| 100 | + | var | |
| 101 | + | l: truths; | |
| 102 | + | begin | |
| 103 | + | l := truths.create(false, true, true, false, true, false, false); | |
| 104 | + | end. | |
| 105 | + | ``` | |
| 106 | + | ||
| 107 | + | Voidaan tietysti käyttä myös sisäkkäisiä taulukoita: | |
| 108 | + | ||
| 109 | + | ``` pascal | |
| 110 | + | program nestedDynamicArrayCreateDemo(input, output, stdErr); | |
| 111 | + | type | |
| 112 | + | truths = array of boolean; | |
| 113 | + | pattern = array of truths; | |
| 114 | + | var | |
| 115 | + | p: pattern; | |
| 116 | + | begin | |
| 117 | + | p := pattern.create( | |
| 118 | + | truths.create(false, false), | |
| 119 | + | truths.create(true, false), | |
| 120 | + | truths.create(true, false, false), | |
| 121 | + | truths.create(true, true, false) | |
| 122 | + | ); | |
| 123 | + | end. | |
| 124 | + | ``` | |
| 125 | + | ||
| 126 | + | ### Käsittely | |
| 127 | + | ||
| 128 | + | Pitää pitää mielessä että dynaamiset taulukot ovat viitteitä. Dynaamisten taulukkomuuttujien "suora kopiointi" toisilleen ei kopioi mitään hyötykuormaa, vaan vain osoiteen. Tämä eroaa staattisten taulukkojen käyttäytymisestä. | |
| 129 | + | ||
| 130 | + | Jos halutaan kopioida tietoja, niin on käytettävä [`system.copy`](https://www.freepascal.org/docs-html/rtl/system/copy.html).-tiedostoa. | |
| 131 | + | ||
| 132 | + | ``` pascal | |
| 133 | + | program dynamicArrayCopyDemo(input, output, stdErr); | |
| 134 | + | ||
| 135 | + | var | |
| 136 | + | foo, bar: array of char; | |
| 137 | + | ||
| 138 | + | procedure printArrays; | |
| 139 | + | begin | |
| 140 | + | writeLn('foo[0] = ', foo[0], '; bar[0] = ', bar[0]); | |
| 141 | + | end; | |
| 142 | + | ||
| 143 | + | begin | |
| 144 | + | setLength(foo, 1); | |
| 145 | + | foo[0] := 'X'; | |
| 146 | + | // copies _reference_ | |
| 147 | + | bar := foo; | |
| 148 | + | write(' initial values: '); | |
| 149 | + | printArrays; | |
| 150 | + | ||
| 151 | + | // change content _via_ _second_ reference | |
| 152 | + | bar[0] := 'O'; | |
| 153 | + | write('changed via 2nd ref: '); | |
| 154 | + | printArrays; | |
| 155 | + | ||
| 156 | + | // copy content | |
| 157 | + | bar := copy(foo, 0, length(foo)); | |
| 158 | + | bar[0] := 'X'; | |
| 159 | + | write(' copied and changed: '); | |
| 160 | + | printArrays; | |
| 161 | + | end. | |
| 162 | + | ``` | |
| 163 | + | ||
| 164 | + | Vain käyttämällä `copy` kopiointia molempia taulukoita voidaan muokata itsenäisesti. | |
| 165 | + | ||
| 166 | + | Kuten edellä todettiin niin tässä `setLength` kopioi tiedot. Yllä olevan esimerkin korostettu rivi vastaa (semanttisesti) `setLength(bar, length(bar))`. | |
| 167 | + | ||
| 168 | + | Dynaamisella taulukolla on "viitelaskuri". Kutsuminen `setLength(myDynamicArrayVariable, 0)` on käytännössä [[Nil/fi|myDynamicArrayVariable := nil]] ja pienentää viitemäärää. Ainoastaan kun viitteiden määrä laskee nollaan, muistilohko vapautetaan. | |
| 169 | + | ||
| 170 | + | ``` pascal | |
| 171 | + | program dynamicArrayNilDemo(input, output, stdErr); | |
| 172 | + | var | |
| 173 | + | foo, bar: array of char; | |
| 174 | + | begin | |
| 175 | + | setLength(foo, 1); | |
| 176 | + | foo[0] := 'X'; | |
| 177 | + | // copy _reference_, increase reference count | |
| 178 | + | bar := foo; | |
| 179 | + | // foo becomes nil, reference count is decreased | |
| 180 | + | setLength(foo, 0); | |
| 181 | + | writeLn('length(foo) = ', length(foo), | |
| 182 | + | '; length(bar) = ', length(bar)); | |
| 183 | + | ||
| 184 | + | // decrease reference count another time | |
| 185 | + | bar := nil; | |
| 186 | + | writeLn('length(foo) = ', length(foo), | |
| 187 | + | '; length(bar) = ', length(bar)); | |
| 188 | + | end. | |
| 189 | + | ``` | |
| 190 | + | ||
| 191 | + | Dynaamiset taulukot kuitenkin loppukäsitellään automaattisesti. Ei tarvitse asettaa manuaalisesti kaikkiin viitteisiin `setLength(…, 0)`, kun ohjelma päättyy tai kun siirrytään osiosta pois. | |
| 192 | + | ||
| 193 | + | Ilman `{$rangeChecks on}` on mahdollista saavuttaa taulukon rajat. Tämä tarkoittaa, että kun iteroidaan dynaamisia taulukkoja, on mahdotonta työskennellä ilman [`low`](https://www.freepascal.org/docs-html/rtl/system/low.html) ja [`high`](https://www.freepascal.org/docs-html/rtl/system/high.html) määrittämään kelvollisia indeksejä (ensimmäinen on valinnainen, koska dynaamiset taulukot alkavat aina nollasta). Vaihtoehtoisesti voidaan käyttää [[for-in loop|for … in looppia silmukoissa]], jos indeksiä ei tarvita. | |
| 194 | + | ||
| 195 | + | Muista, että [[SizeOf|sizeOf]] arvioi dynaamisen taulukon osoittimen koon. | |
| 196 | + | ||
| 197 | + | ## Sovellukset | |
| 198 | + | ||
| 199 | + | - Käytössä on [`system.tBoundArray`](https://www.freepascal.org/docs-html/rtl/system/tboundarray.html) ja [`objPas.tBoundArray`](https://www.freepascal.org/docs-html/rtl/objpas/tboundarray.html) | |
| 200 | + | ||
| 201 | + | ## Katso myös | |
| 202 | + | ||
| 203 | + | - [[String|string]] | |
| 204 | + | - esimerkki: [[Example: Multidimensional dynamic array|multidimensional dynamic array]] | |
| 205 | + | - [Free Pascal Reference guide: “Dynamic arrays”](https://www.freepascal.org/docs-html/ref/refsu14.html#x38-510003.3.1) | |
| 206 | + | ||
| 207 | + | --- | |
| 208 | + | *From the Free Pascal wiki, page "Dynamic array/fi", as it stood on 2022-08-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
