Ero sivun ”C” versioiden välillä

Poistettu sisältö Lisätty sisältö
Tigru (keskustelu | muokkaukset)
→‎Osoittimet: lohkaisen
Tigru (keskustelu | muokkaukset)
Rivi 29:
* [[/Osoittimet/]]
 
==* [[/Dynaaminen muistinvaraus ==/]]
 
Kaikki tähän mennessä käsitelty on perustunut <strong>stack-pohjaiseen muistinvaraukseen</strong>, jossa muisti varataan muuttujan määrittelyn kohdalla ja vapautetaan heti ko. <strong>lohkosta</strong> (engl <strong>block</strong>, <tt>{ /* ... */ int muuttuja; /* ... */ }</tt>) poistuttaessa. Normaalisti et voi tällöin muuttujaa yrittääkään käyttää, koska sitä ei ole olemassa (kääntäjä antaa virheilmoituksen), mutta pointtereilla tätä rajoitusta on mahdollista kiertää, mutta niin ei saa tehdä (jos muuttujaan yrittää päästä käsiksi myöhemmin, ohjelma <emph>saattaa</emph> kaatua - sinua on varoitettu).
 
Stack-allokaation vaihtoehtona on <tt>heap-pohjainen muistinkäsittely</tt>, jossa vastuu muistin varaamisesta ja vapauttamisesta siirtyy ohjelmoijalle. Tällöin kerran tehty muistivaraus (esim. int-arvon tallennustilaksi) säilyy, vaikka lohkosta poistutaan, aina siihen saakka kunnes ohjelmoija erikseen vapauttaa muistin. Muistin varaamista varten täytyy kuitenkin tietää kuinka monta tavua muistia tarvitaan.
 
Tietyn muuttujan tai tietotyypin viemän tilan tavuina saa selvitettyä <tt>sizeof()</tt>-operaattorilla, joka antaa koon tavuina, int-tyyppisenä lukuna, esim. <tt>sizeof(muuttuja)</tt> tai <tt>sizeof(int)</tt>. Kokoja ei kuitenkaan kannata turhan tarkkaan opiskella, sillä ne voivat vaihdella järjestelmästä toiseen (esim. 64-bittisellä Windowsilla sizeof(long int) on 8 tavua, kun 32-bittisellä se on vain 4 tavua). Yleisimpien tyyppien koot omalla koneellasi on kuitenkin hyvä tietää siinä vaiheessa kun ohjelmassasi on muistinkäsittelyvirhe ja yrität Valgrindin (muistivuotodebuggeri) tulosteesta selvittää missä vika on.
 
Muistia varataan funktiolla <tt>malloc</tt>, joka ottaa argumenttinaan tarvittavan muistin määrän tavuina ja palauttaa pointterin varattuun muistialueeseen. Vapauttamiseen käytetään funktiota <tt>free</tt>, joka ottaa parametrinaan pointterin. Molemmat funktiot, samoin kuin makro <tt>NULL</tt>, on esitelty headerissa <tt><stdlib.h></tt>.
 
// Varaa muistia int:n koon verran, tallenna tulos pointteriin p.
int* p = (int*)malloc(sizeof(int));
// Jos p on NULL (esim. pieleen menneen muistinvarauksen jälkeen), lopeta ohjelma.
if (!p) exit(EXIT_FAILURE);
// Vapauta p:n osoittama muisti (jos p on NULL, ei tämä tee mitään)
free(p);
p = (int*)malloc(10 * sizeof(int)); // Varattiin tilaa kymmenelle int-tyyppiselle arvolle
// Luodaan osoitin, joka osoittaa kolmanteen arvoon
int* q = p + 2;
// Huomaa: ei tarvittu 2 * sizeof(int):ä, vaan kääntäjä hoitaa tämän
// automaattisesti pointterin tyypin mukaisesti lausekkeella p + 2.
*q = 3; // Kolmannen integerin arvo on nyt 3
*(p + 9) = 10; // Kymmenennen integerin arvo on nyt 10
Ohjeita dynaamiseen muistinvaraukseen:
* Tyyppimuunna (castaa) <tt>malloc</tt>:n paluuarvo (tyyppiä <tt>void*</tt>) siihen tyyppiin jonka haluat (esim. <tt>int*</tt>). C-kieli ei tätä vaadi (muuntaa implisiittisestikin), mutta koodisi ei toimi C++:ssa, jos et näin tee.
* Tarkista aina mallocin palauttama osoitin ennen sen käyttöä - jos muistia ei saada varattua, palauttaa <tt>malloc</tt> <tt>NULL</tt>:n.
* Funktion <tt>malloc</tt> tilalla voidaan käyttää funktiota <tt>calloc</tt>, kun muistin halutaan olevan valmiiksi alustettua.
* Vapauta kaikki varaamasi muisti (yhtä monta <tt>free</tt>-kutsua kuin <tt>calloc</tt>/<tt>malloc</tt>-kutsuja).
* Funktiolla <tt>realloc</tt> on mahdollista kasvattaa tai pienentää aiemmin varattua muistialuetta, mutta sitä ei käsitellä tässä sen tarkemmin.
* Älä ikinä vapauta <tt>free</tt>:llä muistia, jota ei ole varattu funktioilla <tt>malloc</tt>, <tt>calloc</tt> tai <tt>realloc</tt>.
 
== Taulukot ==
Noudettu kohteesta ”https://fi.wikibooks.org/wiki/C