C/Dynaaminen muistinvaraus
Kaikki tähän mennessä käsitelty on perustunut pinopohjaiseen 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 osoittimilla 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).
Pinosta (engl. stack) varaamisen vaihtoehtona on kekopohjainen muistinkäsittely, jossa vastuu muistin varaamisesta ja vapauttamisesta siirtyy ohjelmoijalle. Tällöin kerran keosta (engl. heap) 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 osoittimen varattuun muistialueeseen. Vapauttamiseen käytetään funktiota free, joka ottaa parametrinaan osoittimen. Molemmat funktiot, samoin kuin makro NULL, on esitelty headerissa <stdlib.h>.
// Varaa muistia int:n koon verran, tallenna tulos osoittimeen 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; /* vaihtoehtoisesti &p[2] */ // Huomaa: ei tarvittu 2 * sizeof(int):ä, vaan kääntäjä hoitaa tämän // automaattisesti osoittimen 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 |
---|
Yksinkertainen C-kielinen ohjelma — Muuttujat — Operaattorit — Kommentit — Ohjausrakenteet — Funktiot — Osoittimet — Dynaaminen muistinvaraus — Taulukot — Merkkijonot — Tietueet — Esikääntäjä — Otsikkotiedostot C-kielen varatut sanat — Standardikirjasto — Aiheesta muualla |