Muuttujalla on muistissa paikka, jonne sen arvo on tallennettu. Kun luot muuttujan, muuttuja saa pinosta (osa tietokoneen muistia) itselleen tilaa. Osoitin(Engl. pointer) on muuttuja, joka sisältää muistiosoitteen toisen muuttujan muistipaikkaan. Osoitinmuuttujan tyyppi kertoo osoitettavan muuttujan tyypin. Osoittimen arvo voi myös olla NULL, milloin se ei osoita mihinkään. Onkin turvallista alustaa osoittimen alkuarvoksi NULL. NULL-osoitin ei koskaan osoita mihinkään(esim. muistipaikka 0 jota ei voi varata). NULL on esikääntäjän makro joka määritellään stdlib.h -otsaketiedostossa.

Osoittimeen p on tallennettu muuttujan a muistipaikka

Osoitin itse on kooltaan sellainen, että siihen mahtuu mikä tahansa muistiosoite sisälle, usein neljä (32-bittiset arkkitehtuurit) tai kahdeksan (64-bittiset) tavua, mutta et voi tehdä mitään oletuksia tämän pohjalta. Pointterin arvoa ei voi myöskään tallentaa esim. int-tyyppiseen muuttujaan, mutta ruudulle sen voi tulostaa printf:n muotoilusäännöllä %p. Osoittimet ja huono osoittimien hallinta voivat aiheuttaa pahoja, vaikeasti havaittavia virheitä. Osoittimien hallinta kannattaa opetella hyvin ennen vaativampaa työtä.

Osoitintietotyyppit merkitään merkillä * osoitettavan tyypin perässä, ennen muuttujaa, eli float-tyyppiseen arvoon osoittavan muuttujan tyyppi on float*, määrittely esim. float* p = NULL;.

Muuttujan osoitteen saa selville &-operaattorilla, joka laitetaan muuttujan nimen eteen lausekkeessa, jossa osoitetta halutaan käyttää. Ennestään tunnetussa osoitteessa olevaa, eli osoittimen osoittamaa tietoa taasen käytetään laittamalla osoittimen eteen operaattori *. Älä kuitenkaan sekoita tätä operaattoria tietotyypissä käytettäviin *-merkkeihin.

Esimerkkejä osoittimien käytöstä muokkaa

#include <stdio.h>

int main() {
	int x;
	int* y;
	
	y = &x;      //asetetaan osoittimen y -arvoksi x:n muistipaikka
	*y = 32;     //y:n osoittaman muistipaikan arvo on nyt 32 (X:n arvo on siis nyt 32)
	
	//Testitulosteet
	printf(" x = %d\n", x);
	printf("&x = %p\n", (void *)&x);
	printf(" y = %p\n", (void *)y);
	
	return 0;
}

Tuplaosoitus muokkaa

Saattaa olla hankala ymmärtää milloin tarvitaan osoitinta, joka osoittaa toisen osoittimen osoittamaan muistipaikkaan. Sovelluksia kuitenkin löytyy paljon dynaamisen muistinkäsittelyn puolelta.

#include <stdio.h>

int main()	{
	int **pp_i; //Luodaan osoitin, joka osoittaa int* -tyyppiseen muuttujaan.
	int *p_i;
	int i = 0;
	
	p_i = &i;
	pp_i = &p_i;
	*p_i = 3;
	
	printf("%d\n", *p_i);	// Antavat saman
	printf("%d\n", **pp_i);	// tulosteen
	
	return 0;
}

Ohjeita osoittimien käyttöön muokkaa

  • Osoitin on validi vain niin kauan kuin sen osoittama tieto on olemassa (muistia ei vapautettu muuhun käyttöön).
  • Pointtereita käytetään usein tiedon turhan kopioinnin (hidasta) välttämiseksi, mutta jos tietoa on vain hyvin vähän (kuten yksi muuttuja), ei tällä itse asiassa säästetä mitään, sillä itse osoitinkin täytyy kuitenkin kopioida.
  • Älä ikinä määrittele useita pointtereita yhdessä lausekkeessa, esim. int* p1, p2; on ohjelmointivirhe (p2 ei olekaan pointteri, vaan tavallinen int-tyyppinen muuttuja!).
  • Varmista ohjelmasi muistinkäsittelyn toimivuus (myös virheellisillä syötteillä) ensin tutkimalla lähdekoodia huolellisesti, sitten muistivuotodebuggerin avulla.
C-ohjelmointikieli

EtusivuHistoriaTyökalut


Yksinkertainen C-kielinen ohjelmaMuuttujatAritmeettiset operaatiotKommentitOhjausrakenteetFunktiotOsoittimetDynaaminen muistinvarausTaulukotMerkkijonotTietueet


C-kielen varatut sanatStandardikirjastoAiheesta muualla