1. Sissejuhatus
C-keele osutid ja funktsiooni osutid on hädavajalikud efektiivse ja paindliku programmeerimise jaoks. Osuti võimaldab mäluaadressidega otse manipuleerida ning funktsiooni osuti salvestab funktsiooni aadressi, võimaldades kaudset funktsioonide väljakutset. Selles artiklis selgitame osutite ja funktsiooni osutite põhitõdesid ja rakendusi ning käsitleme ka turvalisuse aspekte ja praktilisi näiteid.
2. Osutite põhitõed
2.1 Mis on osuti?
Osuti on spetsiaalne muutuja, mis salvestab teise muutuja mäluaadressi. Osutite abil saab muutuja väärtusele kaudselt ligi pääseda, mis suurendab programmi paindlikkust. Näiteks kasutatakse neid andmete jagamisel funktsioonide vahel või suurte andmestruktuuride tõhusaks manipuleerimiseks.
2.2 Osuti deklareerimine ja kasutamine
Osuti deklareerimiseks lisatakse andmetüübi ette tärn (*
). Näide:
int x = 5;
int* p = &x; // Salvestab x aadressi osutisse p
&
operaator tagastab muutuja aadressi, *
operaator viitab väärtusele, millele osuti osutab.
printf("%d", *p); // Väljund: 5
p
osutab x
aadressile ning *p
abil saab x
väärtuse kätte.
3. Funktsiooni osutite põhitõed
3.1 Funktsiooni osuti definitsioon ja deklareerimine
Funktsiooni osuti on osuti, mis salvestab funktsiooni aadressi ning võimaldab dünaamiliselt erinevaid funktsioone välja kutsuda. Funktsiooni osuti deklareerimisel märgitakse tagastustüüp ja argumentide tüübid.
int (*funcPtr)(int);
See osuti viitab funktsioonile, mis võtab argumendiks int
ja tagastab int
väärtuse.
3.2 Funktsiooni osuti kasutamine
Funktsiooni osuti abil funktsiooni väljakutsumiseks omistatakse funktsiooni aadress osutile ning osutit kasutatakse väljakutsumiseks.
int square(int x) {
return x * x;
}
int main() {
int (*funcPtr)(int) = square;
printf("%d", funcPtr(5)); // Väljund: 25
return 0;
}
Selles näites omistatakse funcPtr
-le square
funktsiooni aadress ning funcPtr(5)
kutsub välja square
funktsiooni.
4. Funktsiooni osutite kasutusnäited
4.1 Funktsiooni osutiga funktsiooni käivitamine
Funktsiooni osutid on eriti kasulikud funktsioonide massiivide loomiseks. Võimalus valida erinevaid funktsioone käivitamise ajal muudab programmi paindlikumaks.
void hello() {
printf("Hellon");
}
void goodbye() {
printf("Goodbyen");
}
int main() {
void (*funcs[2])() = {hello, goodbye};
funcs[0](); // Väljund: Hello
funcs[1](); // Väljund: Goodbye
return 0;
}
Selles näites salvestatakse funcs
massiivi erinevad funktsioonid ja neid saab olukorrast lähtuvalt välja kutsuda.
4.2 Tagasikutse funktsioonid (callback)
Tagasikutse funktsioon tähendab funktsiooni, mis määratakse kutsutavaks teatud sündmuse toimumisel. See võimaldab programmi teatud osi dünaamiliselt muuta.
void executeCallback(void (*callback)()) {
callback();
}
void onEvent() {
printf("Event occurred!n");
}
int main() {
executeCallback(onEvent); // Väljund: Event occurred!
return 0;
}
executeCallback
funktsioonile saab dünaamiliselt anda erinevaid funktsioone, mida siis käivitatakse.

5. Osutid ja struktuurid
5.1 Struktuuri osuti kasutamine
Struktuuri osutite abil saab suuri andmestruktuure tõhusalt töödelda. Struktuuri liikmetele ligipääsemiseks kasutatakse ->
operaatorit.
typedef struct {
int x;
int y;
} Point;
int main() {
Point p = {10, 20};
Point *pPtr = &p;
printf("%d, %d", pPtr->x, pPtr->y); // Väljund: 10, 20
return 0;
}
pPtr->x
pääseb ligi p
struktuuri liikmele x
.
5.2 Struktuuri osuti funktsioonile edastamine
Struktuuri osuti edastamine funktsioonile võimaldab funktsiooni sees struktuuri liikmeid muuta.
void updatePoint(Point *p) {
p->x += 10;
p->y += 20;
}
int main() {
Point p = {10, 20};
updatePoint(&p);
printf("%d, %d", p.x, p.y); // Väljund: 20, 40
return 0;
}
Selles näites muudab updatePoint
funktsioon otse Point
struktuuri liikmeid.
6. Funktsiooni osutite eelised ja tähelepanekud
6.1 Eelised
Funktsiooni osutite kasutamine suurendab programmi laiendatavust ja paindlikkust. Näiteks võimaldab see luua pluginasüsteeme või rakendada sündmuspõhist programmeerimist, kus funktsioone saab dünaamiliselt vahetada. Funktsiooni osutite massiivi abil saab keeruka switch
-lausendi asendada lihtsa tsükliga.
6.2 Tähelepanu punktid
Funktsiooni osutite kasutamisel tuleks pöörata tähelepanu järgmistele aspektidele:
- Tüübikohasus: Kui funktsiooni osuti tüüp ei ühti, võib esineda ootamatut käitumist. Veendu, et funktsiooni prototüüp oleks sobiv.
- Turvariskid: Kui kutsuda välja kehtetu funktsiooni osuti, võib tekkida segmenteerimisviga või muu tõrge. Ära unusta osutite algväärtustamist ning vajadusel kontrolli
NULL
väärtust. - Dereferentsimise risk: Kui osuti ei osuta kehtivale aadressile ja seda dereferentseeritakse, võib programm kokku joosta.
7. Kokkuvõte
Osutite ja funktsiooni osutite mõistmine C-keeles on oluline efektiivse ja paindliku programmeerimise saavutamiseks. Funktsiooni osutite abil saab realiseerida dünaamilisi funktsioonikutsungeid, sündmuspõhist programmeerimist ning mitmeid keerukaid programmeerimisvõtteid. Oluline on mõista osutite põhitõdesid ja rakendada neid turvaliselt ning õigesti.