C/Pointteriluntti
Tässä lunttilapussa käsitellään osoittimista eli pointtereista tärkeimmät asiat (ja varmasti riittävä määrä C-kurssien tenttien läpäisyyn).
Terminologia
[muokkaa | muokkaa wikitekstiä]Muuttuja tarkoittaa muistissa olevaa tilaa, johon voi tallentaa tietoa (C-standardissa lvalue). Muistiosoitteet ja muut arvot voivat myös olla pelkkiä laskutoimitusten tuloksia, joille ei tilaa ole varattu (rvalue).
Osoitin tai pointteri on muuttuja, johon voi tallentaa muistiosoitteen.
Literaali on lausekkeessa esiintyvä vakioarvo, esim. 123 tai "abc".
Operaattorit
[muokkaa | muokkaa wikitekstiä]Seuraavassa taulukossa arvojen tyypit on mainittu sulkeissa käyttäen merkintää T, joka voi olla mikä tahansa tyyppi (int, double, struct Foo, ...) tai jopa pointterityyppi (esim. double**, jolloin T* on double***).
Nimi | Lauseke | Operandit | Tulos | Huomioitavaa |
---|---|---|---|---|
Tähtioperaattori (dereferencing operator) | *foo | Muistiosoite foo (T*) | Osoitteessa foo oleva muuttuja (T) | Poistaa tyypistä yhden tähden. |
Osoiteoperaattori (address-of operator) | &foo | Muuttuja foo (T) | Muistiosoite, jossa foo sijaitsee (T*) | Tähtioperaattorin vastakohta. |
Muistissa liikkuminen | foo + n foo - n n + foo |
Muistiosoite foo (T*) ja kokonaisluku n | Uusi muistiosoite (T*) | n on alkioiden lukumäärä (ei tavuja). |
Pointtereiden erotus | foo - bar | Muistiosoitteet foo (T*) ja bar (T*) | Osoitteiden välinen etäisyys (ptrdiff_t). | Alkioiden lukumäärä (ei tavuja), negatiivinen jos foo < bar. ptrdiff_t on etumerkillinen kokonaislukutyyppi. |
Tyypin koko | sizeof(T) | Tyypin nimi T | T:n viemä tila tavuina (size_t). | Sulkeet tyypin ympärillä ovat pakolliset. size_t on etumerkitön kokonaislukutyyppi. |
Tyypin koko (lausekkeelle) | sizeof foo | Muuttuja tai lauseke foo | sizeof(T), jossa T on foon tyyppi. | Vain foon tyyppi huomioidaan (arvoa ei), joten ei voi käyttää pointteriin merkkijonon tai taulukon koon selvittämiseksi (palauttaa muistiosoitteen koon). |
Indeksointi | foo[n] n[foo] |
Muistiosoite foo ja kokonaisluku n | *(foo + n) | Palauttaa alkion indeksillä n. Muotoa n[foo] ei yleensä käytetä. |
Määrittelyt
[muokkaa | muokkaa wikitekstiä]Kaikki seuraavista määrittelevät muuttujan nimeltä foo, tyyppiä double* (ei siis muuttuja nimeltä *foo, tyyppiä double):
double* foo; double *foo; double * foo;
Määrittelyssä tyypin yhteydessä näkyvää tähteä ei pidä sekoittaa tähtioperaattoriin.
Useiden pointtereiden määrittelyä samalla kertaa kannattaa välttää, sillä tähdet pitää toistaa jokaiselle pointterille erikseen. Seuraavassa yleinen virhe:
int* foo, bar; // foo on pointteri, bar kokonaisluku
Yleensä muuttuja kannattaa alustaa samalla kun sen määrittelee, esim:
double* foo = NULL;
NULL on esikääntäjän makro joka määritellään stdlib.h
-otsaketiedostossa yleensä (void*) 0.
Merkkijonot
[muokkaa | muokkaa wikitekstiä]Merkkijonoliteraali "ab" on sama asia kuin taulukko { 'a', 'b', '\0' } ja sen tyyppi on char[3] (mutta periaatteessa char const[3], sillä siihen ei saa kirjoittaa). Merkkijonon pituuden voi selvittää funktiolla strlen(ptr), joka laskee ptr:stä alkaen merkki kerrallaan eteenpäin kunnes löytyy nollamerkki.
Implisiittiset muunnokset
[muokkaa | muokkaa wikitekstiä]Taulukko muuttuu yleensä laskutoimituksissa välittömästi ensimmäisen alkionsa muistiosoitteeksi. Esim. double[10]-tyyppisestä taulukosta array tulee double*-tyyppinen arvo, kun kirjoitat array + 0. sizeof(array) kertoo taulukon koon tavuina, mutta sizeof(array + 0) kertoo muistiosoitteen koon.
Myös funktion prototyyppiin kirjoitettu taulukkotyyppi muuttuu pointterityypiksi (moniulotteisilla taulukoilla vain ulommaisin taso eli ensimmäinen dimensio muuttuu pointteriksi). Esimerkiksi funktion esittely ja määrittely voidaan kirjoittaa eri tavoin, koska kumpikin kuitenkin tarkoittaa samaa:
void f(char* strings[]); void f(char** strings) {}