Tietojenkäsittelytieteessä **osoitin** (engl. *pointer*) on tietotyyppi, joka viittaa keskusmuistissa sijaitsevaan arvoon. Osoitin-tyyppistä muuttujaa voidaan kutsua **osoitinmuuttujaksi** tai pelkästään osoittimeksi. Osoitinmuuttuja sisältää viitattavan arvon muistiosoitteen. Toisin kuin viitettä, osoitinta voi kasvattaa, sitä voi verrata toiseen osoittimeen ja siihen voi sijoittaa tunnetun muistiosoitteen lukuarvona. Osoittimia käytetään paljon erityisesti C- ja C++-ohjelmointikielillä kirjoitetuissa ohjelmissa.

Keskusmuistia voi ajatella suurena taulukkona, jonka ensimmäisen tavun indeksi on 0, toisen 1 ja niin edelleen. Osoittimet ovat vain indeksejä keskusmuistiin.

Käyttö
------

### Osoitteen sijoitus

C:ssä ja C++:ssa osoittimeen voidaan sijoittaa muistiosoite seuraavasti:

```
 int luku;
 int \*osoitin;
 osoitin = &luku;

```

&-merkki luetaan "address of" eli yllä "*osoitin* saa arvokseen muuttujan *luku* osoitteen".

### Arvon noutaminen

Osoitteesta voidaan noutaa arvo (engl. *dereference*, toisinaan suomeksi *osoittimen seuraaminen*):

```
 int toinen\_luku;
 toinen\_luku = \*osoitin;

```

Yllä oleva luetaan "*toinen\_luku* saa arvokseen *osoittimen* osoittaman kokonaislukuarvon".

### Aritmetiikka

Useimmissa ohjelmointikielissä osoittimet eivät osoita vain tavuihin, vaan esimerkiksi useita tavuja pitkiin kokonaislukuihin. Osoittimen kasvattaminen yhdellä kasvattaa sitä osoittimen tietotyypin pituuden verran. Tämä yksinkertaistaa taulukoiden läpikäyntiä:

```
// alustaa taulukon T alkiot luvulla 1
int T[10];
int\* p = T; // T on osoitin kokonaislukuun, joka osoittaa "taulukon" T alkuun, eli osoitteeseen &T[0]
while (p < T+10) // osoittimia voi vertailla kuin lukuja; tarkoittaa samaa kuin p < &T[10]
{
 \*p = 1;
 ++p; // kasvatetaan osoitinta yhdellä
 // -> osoite kasvaa osoittimen tietotyypin
 // (kokonaisluvun) pituuden verran
 // eli seuraavaan taulukon lukuun
}

```

### Null-osoitin

Osoittimelle voidaan antaa arvoksi *null*, tyhjä. Kyseistä osoitinta kutsutaan silloin null-osoittimeksi (toisinaan *nollaosoitin*). Se on erikoisarvo, joka tarkoittaa että osoitin ei osoita minnekään. Null-arvoa käytetään aliohjelman parametrina ja palautusarvona välittämään jokin erikoismerkitys ("aliohjelma käyttäköön oletusarvoa", "muisti loppui") ja päättämään linkitettyjä tietorakenteita kuten linkitetyn listan.

Sisäisesti null-arvo on usein luku 0, sillä useissa käyttöjärjestelmissä ensimmäisen muistisivun käyttö on vikatilanne. C-kielessä usein käytetään NULL-makroa, joka on sama kuin kokonaisluku 0.

```
 int \*p;
 p = 0;
 (\*p) = 42;

```

C++11-standardissa C++-kieleen lisättiin `nullptr`-osoiteliteraali. Se on tyyppiä `nullptr_t` toisin kuin C-kielen NULL-makro.

```
 int \*p = nullptr;
 (\*p) = 42; // vikatilanne: osoitin ei ole validi osoite

```

Huomaa, että eräillä alustoilla voi olla mahdollista että käyttöjärjestelmän kerneli viittaa ensimmäiseen muistisivuun osoitteessa nolla. 

Näin ollen `int *p = 0;` voi olla tietyissä tapauksissa validi kun taas `int *p = nullptr;` ei ole missään tilanteessa validi viittaus ja on yksiselitteinen.

### Funktio-osoitin

Osoitin voi osoittaa myös ohjelmakoodiin. Piirrettä käytetään funktio-osoittimien muodossa:

```
 void draw\_directx() {
 // koodia
 }
 void draw\_opengl() {
 // koodia
 }

 // funktio-osoitin draw saa arvokseen funktion draw\_opengl osoitteen
 void (\*draw)() = draw\_opengl;

```

Funktio-osoittimia käytetään mm. C-kielessä ja C++-kielessä.

Funktio-osoittimilla voidaan toteuttaa kielen omia toimintoja, sekä dynaamisesti ladatun ohjelmakoodin *liitos* (engl. *binding*) funktion *tynkään* ajonaikaisesti (ks. DLL). Virtuaaliosoitin on funktio-osoittimen käyttötapaus olio-ohjelmoinnissa, jossa perintää käyttäessä voidaan yläluokassa oleva toteutus korvata toisella.

Suorituskyky
------------

Tietokone käsittelee osoittimia kuin kokonaislukuja eikä niihin liity minkäänlaisia tarkistuksia, joten ne ovat hyvin nopeita. Joskus taulukko voidaan periaatteessa käydä läpi nopeammin osoittimilla kuin for-lauseella indeksoimalla, mutta todellisuudessa ero on mitätön, ja kääntäjä kuitenkin optimoi molemmat keinot tehokkaimmaksi mahdolliseksi.

Osoittimen varaama muistimäärä vaihtelee sekä käyttöjärjestelmän että suorittimen mukaan. Tyypillisesti 32-bittisissä koneissa osoitin on 32 bittiä ja 64-bittisissä osoitin on 64 bittiä. 

Tyypillisesti ohjelman suorituksen kannalta on nopeampaa antaa aliohjelmalle parametrina vain osoitin tietueeseen kuin monta erillistä parametria, sillä tällöin aliohjelmaa varten riittää työntää ajonaikaiseen pinoon vain yksi muistiosoite.

Turvallisuus
------------

Osoittimien huolimaton käyttö saattaa aiheuttaa muistivuotoja ja vaikeasti jäljitettäviä ohjelmointivirheitä, sekä antaa krakkerille mahdollisuuden hyökätä ohjelman käyttäjän koneelle. Niinpä useimmissa sovellus- tai Web-ohjelmointiin suunnatuissa kielissä, kuten Javassa, PHP:ssa, Pythonissa tai Rubyssä, ei ole osoittimia, ja C#-kielessä niitä ei juuri käytetä.

Tuki ohjelmointikielissä
------------------------

Seuraavat ohjelmointikielet tukevat osoittimia:

* Ada 95
* C
* C++
* C# (lähinnä C/C++:lla kirjoitettujen ohjelmakirjastojen käyttämiseen)
* D
* Fortran 90
* Go
* Modula-2
* Oberon
* Pascal
* Perl

Katso myös
----------

* Viitelaskenta
* Älyosoitin

Lähteet
-------

1. ↑  Tarjei Mandt: Locking Down the Windows Kernel: Mitigating Null Pointer Exploitation (PDF) *mista.nu*. Viitattu 19.5.2018.
2. ↑  Michael O’Boyle: Operating Systems Paging (PDF) *inf.ed.ac.uk*. Viitattu 19.5.2018.
3. ↑  nullptr, the pointer literal *en.cppreference.com*. Viitattu 6.2.2017.

Aiheesta muualla
----------------

CommonsCommons
Wikimedia Commonsissa on kuvia tai muita tiedostoja aiheesta **Osoitin (ohjelmointi)**.
* Wikikirjasto: C/Osoittimet