C/Dynaaminen muistinvaraus

Wikikirjastosta
< C

Kaikki tähän mennessä käsitelty on perustunut stack-pohjaiseen muistinvaraukseen, jossa muisti varataan muuttujan määrittelyn kohdalla ja vapautetaan heti ko. lohkosta (engl block, { /* ... */ int muuttuja; /* ... */ }) 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 saattaa kaatua - sinua on varoitettu).

Stack-allokaation vaihtoehtona on heap-pohjainen muistinkäsittely, 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ä sizeof()-operaattorilla, joka antaa koon tavuina, int-tyyppisenä lukuna, esim. sizeof(muuttuja) tai sizeof(int). 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 malloc, joka ottaa argumenttinaan tarvittavan muistin määrän tavuina ja palauttaa pointterin varattuun muistialueeseen. Vapauttamiseen käytetään funktiota free, joka ottaa parametrinaan pointterin. Molemmat funktiot, samoin kuin makro NULL, on esitelty headerissa <stdlib.h>.

// 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) malloc:n paluuarvo (tyyppiä void*) siihen tyyppiin jonka haluat (esim. int*). 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 malloc NULL:n.
  • Funktion malloc tilalla voidaan käyttää funktiota calloc, kun muistin halutaan olevan valmiiksi alustettua.
  • Vapauta kaikki varaamasi muisti (yhtä monta free-kutsua kuin calloc/malloc-kutsuja).
  • Funktiolla realloc on mahdollista kasvattaa tai pienentää aiemmin varattua muistialuetta, mutta sitä ei käsitellä tässä sen tarkemmin.
  • Älä ikinä vapauta free:llä muistia, jota ei ole varattu funktioilla malloc, calloc tai realloc.
  • Älä ikinä vapauta free:llä jo sillä kerran vapautettua muistia.
C-ohjelmointikieli

EtusivuHistoriaTyökalut


Yksinkertainen C-kielinen ohjelmaMuuttujatAritmeettiset operaatiotKommentitOhjausrakenteetFunktiotOsoittimetDynaaminen muistinvarausTaulukotMerkkijonotTietueet


C-kielen varatut sanatStandardikirjastoAiheesta muualla