Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Muotoiltu koodit {code} osioihin selkeyden vuoksi, ei asiamuutoksia

...

Osoitinmuuttujat

...

ja

...

muuttujan

...

osoite

...

Simppeli esimerkki

Muuttuja voi sisältää arvon tai osoitteen. Kun tietoa täytyy välittää funktioille suuri määrä yhdellä kertaa tai, kun tiedonkulun on oltava kaksisuuntaista, täytyy tieto välittää osoitteen avulla. Esimerkiksi haluttaessa välittää taulukko toiselle funktiolle, annetaan tyypillisesti kutsuttavalle funktiolle tiedoksi paikka, missä kohdassa muistia taulukko sijaitsee, eikä kaikkia taulukon alkioita erikseen. Kaikki merkkijonot välitetään funktioilta toiselle osoitteiden avulla. Osoitinmuuttuja esitellään seuraavasti:

Code Block
int* OsoitinKokonaisLukuun;
float* OsoitinReaalilukuun;
char* OsoitinMerkkiinTaiMerkkijonoon;
double* OsoitinPitkaanReaalilukuun;
void *Tavuosoitin;

Tähti tyypin ja muuttujan nimen välissä kertoo, että kyseessä on osoitin. p kirjainta käytetään usein muuttujan edessä ilmoittamaan tätä (p = pointer = osoitin). Edellä esitellyillä osoitinmuuttujilla voidaan nyt osoittaa vastaavan tyypin muuttujiin. Osoittimen esittelyn jälkeen, osoitin on ns. "villi" osoitin (wild pointer), koska se ei osoita vielä mihinkään. Tällaisen osoittimen käyttö on erittäin vaarallista. Monesti osoitin laitetaan osoittamaan "ei minnekään" seuraavalla tavalla:

Code Block
int* pLuku=NULL;

Edellä esitetty esittely takaa sen ettei ko. osoitinta voi käyttää ennen kuin se on alustettu osoittamaan jotain muuttujaa esim. seuraavasti:

Code Block
 esimerkki]

\#include <stdio.h>
Muuttuja voi sisältää arvon tai osoitteen. Kun tietoa täytyy välittää funktioille suuri määrä yhdellä kertaa tai, kun tiedonkulun on oltava kaksisuuntaista, täytyy tieto välittää osoitteen avulla. Esimerkiksi haluttaessa välittää taulukko toiselle funktiolle, annetaan tyypillisesti kutsuttavalle funktiolle tiedoksi paikka, missä kohdassa muistia taulukko sijaitsee, eikä kaikkia taulukon alkioita erikseen. Kaikki merkkijonot välitetään funktioilta toiselle osoitteiden avulla. Osoitinmuuttuja esitellään seuraavasti:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int\* OsoitinKokonaisLukuun;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float\* OsoitinReaalilukuun;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char\* OsoitinMerkkiinTaiMerkkijonoon;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double\* OsoitinPitkaanReaalilukuun;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; void \*Tavuosoitin;

Tähti tyypin ja muuttujan nimen välissä kertoo, että kyseessä on osoitin. p kirjainta käytetään usein muuttujan edessä ilmoittamaan tätä (p = pointer = osoitin). Edellä esitellyillä osoitinmuuttujilla voidaan nyt osoittaa vastaavan tyypin muuttujiin. Osoittimen esittelyn jälkeen, osoitin on ns. "villi" osoitin (wild pointer), koska se ei osoita vielä mihinkään. Tällaisen osoittimen käyttö on erittäin vaarallista. Monesti osoitin laitetaan osoittamaan "ei minnekään" seuraavalla tavalla:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int\* pLuku=NULL;

Edellä esitetty esittely takaa sen ettei ko. osoitinta voi käyttää ennen kuin se on alustettu osoittamaan jotain muuttujaa esim. seuraavasti:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int Luku;//esitellään muuttuja nimeltään Luku
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pLuku=&Luku;//Sijoitetaan muuttujan Luku osoite osoiteeseen pLuku
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(pLuku==NULL) printf("VIRHE, LUVATON OSOITTIMEN KÄYtTÖKÄYTTÖ");

&-merkillä

...

haetaan

...

esitellyn

...

muuttujan

...

osoite.

...

Osoitetta

...

vastaava

...

muuttuja

...

Monessa

...

tapauksessa

...

tiedetään,

...

missä

...

tieto

...

on

...

eli

...

tiedetään

...

tiedon

...

osoite.

...

Esim.

...

kaikki

...

tietokoneeseen

...

liitetyt

...

laitteet

...

ovat

...

tietyissä

...

osoitteissa.

...

Osoitetta

...

vastaava

...

muuttuja

...

saadaan

...

*

...

merkillä. esim.

Code Block
 esim.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char Merkki;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char\* pSarjaportti=0x0238;//sarjaportti on liitetty osoitteeseen 0x238
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Merkki= \*pSarjaportti;

Esim.

Code Block


Esim.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int Eka=5;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int \*pLuku=NULL;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int OmaLuku=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pLuku = &Eka;//pLuku osoittamaan OmaLuku muuttujaa
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OmaLuku = \*pLuku;//pLuku osoitteen osoittaman muistipaikan sisältö OmaLuku muuttujalle

Edellä

...

olevassa

...

esimerkissä

...

muuttujaan

...

Eka

...

sijoitetaan

...

arvo

...

viisi,

...

pLuku

...

laitetaan

...

osoittamaan

...

muuttujaa

...

Eka.

...

Seuraavaksi

...

haetaan

...

pLukua

...

vastaava

...

muuttuja

...

*:llä

...

ja

...

sijoitetaan

...

se

...

muuttujaan

...

OmaLuku

...

Osoitin

...

osoittaa

...

muuttujan

...

paikkaa

...

muistissa.

...

Osoitinmuuttuja

...

on

...

erityinen

...

muuttuja,

...

joka

...


sisältää

...

tiettyyn

...

tyyppiin

...

määritellyn

...

osoittimen.

...

Osoittimilla

...

on

...

C-kielessä

...

kolme

...

tärkeää

...

tehtävää:

...

niillä

...

voidaan

...

osoittaa

...

nopeasti

...

vektorin

...

tai

...

taulukon

...

elementteihin,

...

ne

...

mahdollistavat

...

kaksisuuntaisen

...

tiedon

...

siirron

...

funktioiden

...

välillä

...

ja

...

kolmantena

...

ne

...

tukevat

...

linkattuja

...

listoja

...

ja

...

dynaamisia

...

tietorakenteita.

...

Osoittimien

...

oikea

...

ymmärtäminen

...

on

...

erittäin

...

tärkeää

...

tehokkaan

...

C-ohjelmoinnin

...

kannalta.

...

Osoittimet

...

ovat

...

yksi

...

C:n

...

vahvimmista,

...

mutta

...

myös

...

vaarallisimmista

...

piirteistä.

...

Alustamaton

...

osoitin

...

saattaa

...

aiheuttaa

...

koko

...

ohjelman

...

romahtamisen

...

ja

...

mikä

...

pahinta

...

osoittimien

...

aiheuttamia

...

virheitä

...

on

...

erittäin

...

vaikea

...

löytää,

...

koska

...

ohjelman

...

antamat

...

virheilmoitukset

...

ko.

...

tapauksessa

...

osoittavat

...

tyypillisesti

...

väärään

...

paikkaan.

...

Lisäksi

...

ohjelma

...

saattaa

...

toimia

...

pitkiäkin

...

aikoja

...

näennäisen virheettömästi.

Code Block
 virheettömästi.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int Luku;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int\* pLuku;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int*\* ppLuku;

&nbsp;&

   Osoitteen osoite           Osoite                    Muuttuja
   &&Luku                         &Luku                   Luku
   &pLuku                         pLuku                    *pLuku
   ppLuku                         *ppLuku                 **ppLuku

Yllä oleva taulukko esittää, kuinka voidaan siirtyä muuttujasta sen osoitteeseen ja päin vas-
toin.

Tiedonvälitys osoitteiden avulla

Esimerkki tiedonvälityksestä osoittimen avulla.

Code Block
//esittelyt
nbsp; Osoitteen osoite&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Osoite&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Muuttuja
&nbsp;&nbsp; &&Luku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &Luku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Luku
&nbsp;&nbsp; &pLuku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; pLuku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;*pLuku
&nbsp;&nbsp; ppLuku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; \*ppLuku&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \**ppLuku

Yllä oleva taulukko esittää, kuinka voidaan siirtyä muuttujasta sen osoitteeseen ja päin vas\-
toin.

h2. Tiedonvälitys osoitteiden avulla

Esimerkki tiedonvälityksestä osoittimen avulla.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //esittelyt
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void JokuFunktio(int*);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void main();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    void main()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {
	int Luku=5; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
	JokuFunktio(&Luku); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
	printf("Luvun arvo on %d",Luku); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getch(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
	getch();
}
void JokuFunktio(int\* pMuuttuja)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \{
	*pMuuttuja = \*pMuuttuja * 2; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
Tähdellä on kolme merkitystä:
\* hakee osoitetta vastaavan muuttujan
\* esittelee osoitinmuuttujan
\* toimii myös kertomerkkinä

h2. Osoittimen määrittäminen vektorille

Osoitin vektorille on vektorin nimi ilman indeksiä.
Esim.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp
}

Tähdellä on kolme merkitystä:
* hakee osoitetta vastaavan muuttujan
* esittelee osoitinmuuttujan
* toimii myös kertomerkkinä

Osoittimen määrittäminen vektorille

Osoitin vektorille on vektorin nimi ilman indeksiä.
Esim.

Code Block
int p*;       //kokonaislukuosoitin
int testi[20]; //;&nbsp;  int p*;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*kokonaislukuosoitin*/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int testi\[20\]; /*20:n kokonailuvun vektori*/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p = testi;&nbsp;&nbsp;&nbsp;&nbsp; /*     //kokonaislukuvektorin ensimmäisen elementin osoitin sijoitetaan osoittimen p arvoksi*/

Edellenen

...

käsky

...

voidaan

...

toteuttaa

...

myös

...

& merkillä

Code Block
 merkillä
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testi = &testi\[0\];

h2. Osoitinaritmetiikkaa

Osoittimiin voidaan kohdistaa ainoastaan kaksi laskutoimitusta, yhteen\- ja vähennyslasku.
Laskenta on turvallisinta \+\+ ja \-\- operaattoreita käyttäen, jotta osoitin osoittaa aina muuttujan
alkuun.
&nbsp;

Osoitinaritmetiikkaa

Osoittimiin voidaan kohdistaa ainoastaan kaksi laskutoimitusta, yhteen- ja vähennyslasku.
Laskenta on turvallisinta ++ ja -- operaattoreita käyttäen, jotta osoitin osoittaa aina muuttujan
alkuun.

Code Block
int *p;
float *f;
int lukuja[10];
float flukuja[10];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int \*p;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; float \*f;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int lukuja\[10\];
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; float flukuja\[10\];
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p=lukuja;//laitetaan kokonaislukuosoitin osoittamaan vektorin alkuun
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; f=flukuja;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; p++;//siirrytään seuraavaan alkioon
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; f++;

p:n

...

arvo

...

nousee

...

laskutoimituksessa

...

kahdella

...

ja

...

f:n

...

arvo

...

kahdeksalla(riippu

...

ympäristöstä,

...

tarkasta

...

sizeof

...

funktiolla

...

lukualueiden

...

koko),

...

koska

...

kokonaisluku

...

on

...

kaksi

...

tavua

...

ja

...

liukuluku

...

kahdeksan

...

tavua

...

pitkä.

...

Osoittimien

...

vertailu

...

Osoittimia

...

voidaan

...

vertailla

...

keskenään esim.

Code Block
 esim.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (p<q) printf("p osoittaa pienempään muistiosoitteeseen kuin q");

Osoitinvertailuja

...

joudutaan

...

käyttämään

...

erityisesti

...

tapauksissa,

...

joissa

...

tarvitaan

...

pinoa.

...

Tyypillisiä

...

sovellutuksia

...

ovat

...

kääntäjät,

...

tulkit

...

ja

...

taulukkolaskentaohjelmat.

...

(eli

...

ei

...

tavallista)

...

Osoittimet

...

ja

...

vektorit

...

Osoittimien

...

ja

...

vektoreiden

...

välillä

...

on

...

läheinen

...

yhteys esim.

Code Block
 esim.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char strMerkkiJono\[80\], \*psrtMerkkiJono;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; psrtMerkkiJono = strMerkkiJono;

p1

...

asetettiin

...

osoittamaan

...

ensimmäistä

...

vektorin

...

elementtiä.

...

Kun

...

halutaan

...

osoittaa

...

neljättä

...

el

...

-

...


ementtiä,

...

voidaan

...

kirjoittaa:
        str[3]
tai
        *(p1+3)

...


Vektoreita

...

voidaan

...

osoittaa

...

osoitinaritmetiikalla

...

tai

...

vektorin

...

indeksien

...

avulla.

...

Osoitin

...

arit

...

-

...


metiikka

...

on

...

ohjelman

...

kannalta

...

nopeampi

...

tapa.

...

...

void osoitin

void-tyyppinen

...

osoitin

...

on

...

ns.

...

geneerinen

...

osoitin.

...

Geneerinen

...

osoitin

...

voi

...

osoittaa

...

minkä

...

tahansa

...

tyypin

...

muuttujaan.

...

Esimerkiksi

...

seuraavat

...

ohjelmalauseet

...

ovat sallittuja.

Code Block
 sallittuja.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char MerkkiJono\[80\];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void\* OsoitinMihintahansa=NULL;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OsoitinMihintahansa=Merkkijono;

Geneerisen

...

osoittimen

...

inkrementointi

...

ja

...

degrementoinit

...

muuttavat

...

osoittimen

...

asemaa

...

yhden

...

tavun

...

verran.

...

Geneerisiä

...

osoittimia

...

käytetään

...

tyypillisesti

...

laiteläheisessä

...

ohjelmoinnissa.

...

Osoitin paluuarvona

Paikallisen muuttujan osoitetta ei saa palauttaa, koska paikallinen muuttuja häviää funktiosta poistuttaessa.

Code Block
int

----
h2. Osoitin paluuarvona

Paikallisen muuttujan osoitetta ei saa palauttaa, koska paikallinen muuttuja häviää funktiosta poistuttaessa.

int\* funktio()
{
	int a;      				// tilapäinen muuttuja, vapautetaan funktiosta poistuttaessa
	int \*tulos = &a; 	// sijoitetaan tulos-osoittimeen a:n muistipaikan osoite
	return tulos;		// VIRHE\!\!\!  a on paikallinen muuttuja
}

Oikea

...

ratkaisu

Code Block


int\* funktio(int\* a) //a on nyt kutsujan jonkin muuttujan osoite
{

	int \*tulos = a; // sijoitetaan tulos-osoittimeen a:n osoite
	return tulos;		 // OIKEIN
}

 

Toinen

...

mahdollinen

...

ratkaisu

Code Block


int\* funktio()
{
	static int a;      // staattista muuttujaa ei vapauteta funktiosta poistuttaessa
	int \*tulos = &a; // sijoitetaan tulos-osoittimeen a:n muistipaikkan osoite
	return tulos;		 // VIRHE\!\!\!
}