Osutajad C-s: Mis on osuti C-programmeerimises? Tüübid
⚡ Nutikas kokkuvõte
C-keeles on pointerid muutujad, mis salvestavad teise muutuja mäluaadressi. Need võimaldavad dünaamilist mälujaotust, tõhusat massiivide ja stringide käsitlemist ning keerukate andmestruktuuride loomist, kasutades väärtuste lugemiseks või muutmiseks operaatoreid address-of ja dereference.

Mis on pointer C-keeles?
A pointer C-keeles on muutuja , mis salvestab teise muutuja aadressi. Pointer võib viidata ka teisele pointerile või funktsioonile. Pointerit saab suurendada või vähendada, et see osutaks järgmisele või eelmisele mäluasukohale. Pointeri eesmärk on säästa mäluruumi ja saavutada kiirem täitmisaeg.
Osutajate kasutamine C-s
Kui deklareerime int-tüüpi muutuja v, siis v salvestab väärtuse. Igal muutujal on lisaks väärtusele ka aadress, st koht mälus. Aadressi saab kätte, kui muutaja nime ette panna ja-märk (&). Muutuja aadressi väljatrükkimisel näeb see välja nagu juhuslik arv, mis võib täitumisel erineda.
Väärtuse salvestamise asemel salvestab pointer muutuja aadressi. Näiteks:
int *y = &v;
| MUUTUV | PUNKT |
|---|---|
| A väärtus ladustatud a nimetatud salvestus-/mäluaadress. | A muutuja et osutab salvestus-/mäluaadress teine muutuja. |
Osuti deklareerimine
Nagu muutujad, viitavad sisse C programmeerimine tuleb enne kasutamist deklareerida. Pointeri deklaratsioonil on järgmine vorm:
data_type *pointer_variable_name;
Siin andmetüüp on pointeri baastüüp ja näitab muutuja tüüpi, millele pointer osutab. Tärn (*), sama sümbol, mida kasutatakse korrutamisel, on kaudse operaatori operaator, mis deklareerib pointeri. Mõned kehtivad pointeri deklaratsioonid on:
int *ptr_thing; /* pointer to an integer */ int *ptr1, thing; /* ptr1 points to an int; thing is an int */ double *ptr2; /* pointer to a double */ float *ptr3; /* pointer to a float */ char *ch1; /* pointer to a character */
Pointeri initsialiseerimine
Pärast pointeri deklareerimist initsialiseerime selle muutuja aadressiga. Kui pointer on initsialiseerimata ja seda kasutatakse, võivad tulemused olla ettearvamatud ja potentsiaalselt katastroofilised. Muutuja aadressi saamiseks kasutage muutuja nime ees ampersandi (&) operaatorit:
pointer = &variable;
Lihtne programm, mis illustreerib pointerit, on toodud allpool:
#include <stdio.h> int main() { int a = 10; // variable declaration int *p; // pointer variable declaration p = &a; // store address of a in pointer p printf("Address stored in p is: %x\n", p); // access the address printf("Value stored in p is: %d\n", *p); // access the value return 0; }
Väljund:
Address stored in p is: 60ff08 Value stored in p is: 10
| Operator | Tähendus |
|---|---|
| * | Teenib kahte eesmärki: deklareerib pointeri ja tagastab viidatud muutuja väärtuse (viite eemaldamine). |
| & | Teenib ühte eesmärki: tagastab muutuja aadressi. |
Osutite tüübid C-s
Nullkursor
Null-pointeri loomiseks määrame deklareerimise ajal väärtuse NULL. See on kasulik, kui pointerile pole veel aadressi määratud. Null-pointer sisaldab alati väärtust 0:
#include <stdio.h> int main() { int *p = NULL; // null pointer printf("The value inside variable p is: %x", p); return 0; }
Tühi osuti
Tühja osuti, mida nimetatakse ka üldiseks osutiks, ei oma standardset andmetüüpi. See luuakse märksõna void abil ja see saab salvestada mis tahes muutuja aadressi:
#include <stdio.h> int main() { void *p = NULL; // void pointer printf("The size of pointer is: %d\n", sizeof(p)); return 0; }
Metsik pointer
Pointerit nimetatakse metsik-pointeriks, kui see pole millekski initsialiseeritud. Need pointerid ei ole efektiivsed, kuna need võivad osutada tundmatule mäluasukohale, mis võib põhjustada probleeme ja programmi krahhi. Olge metsik-pointeritega alati ettevaatlik:
#include <stdio.h> int main() { int *p; // wild pointer printf("%d", *p); return 0; }
Muud tüüpi C-keele pointerid hõlmavad rippuvat pointerit, kompleksset pointerit, lähipointerit, kaugpointerit ja hiiglaslikku pointerit.
Otsesed ja kaudsed pääsuosad
C-keeles on muutuja sisule juurdepääsuks ja selle muutmiseks kaks samaväärset viisi. Otsejuurdepääs kasutab otse muutuja nime, kaudne juurdepääs aga muutujale viitavat kursorit:
#include <stdio.h> int var = 1; /* declare and initialize an int variable */ int *ptr; /* declare a pointer to int */ int main(void) { ptr = &var; /* point ptr to var */ printf("\nDirect access, var = %d", var); printf("\nIndirect access, var = %d", *ptr); *ptr = 48; /* change var through the pointer */ printf("\nIndirect access, var = %d", *ptr); return 0; }
Osuti aritmeetika C-s
Pointeritega töötamisel järgige neid prioriteedireegleid. Operaatoritel * ja & on sama prioriteet kui unaaroperaatoritel (eitus !, juurdekasv ++, kahandamine –). Samas avaldises hinnatakse unaaroperaatoreid *, &, !, ++ ja — paremalt vasakule. Kui pointer P osutab muutujale X, siis saab *P-d kasutada kõikjal, kus X saab kirjutada. Järgmised avaldised on samaväärsed:
| Väljendus | Ekvivalentne väljend |
|---|---|
| Y = *P + 1 | Y = X + 1 |
| *P = *P + 10 | X = X + 10 |
| *P + = 2 | X + = 2 |
| ++*P | ++X |
| (*P)++ | X++ |
Viimasel juhul on sulud kohustuslikud: kuna unaarsed operaatorid * ja ++ hinnatakse paremalt vasakule, siis ilma sulgudeta suurendataks pointerit P, mitte objekti, millele see osutab. Pointeritel saadaolevad aritmeetilised tehted on omistamine, suurendamine ja vähendamine ning liitmine või sub.tractäisarvulise nihke määramine, mis liigutab pointerit selle arvu elementide võrra (iga samm võrdub baastüübi suurusega baitides).
C-keele pointerid ja massiivid näidetega
Tavaliselt pääseme massiivi elementidele ligi indeksi abil, aga pointerid teevad selle ka lihtsaks. Massiivi nimele seatud pointer osutab esimesele elemendile:
#include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; // array initialization int *p; // pointer declaration p = a; // p points to the first element; same as &a[0] for (int i = 0; i < 5; i++) { printf("%d\n", *p); // print element p++; // move to the next element } return 0; }
Numbri lisamine osutile liigutab seda nii mitu elementi edasi. Kui p osutab mäluasukohale 0, siis p + 1 paneb osuti osutama mäluasukohale 1.
C Osutajad ja stringid koos näidetega
String on char-objektide massiiv, mis lõpeb nullmärgiga '\0'. Me saame stringe manipuleerida pointerite abil:
#include <stdio.h> #include <string.h> int main() { char str[] = "Hello Guru99!"; char *p; p = str; printf("First character is: %c\n", *p); p = p + 1; printf("Next character is: %c\n", *p); p = str; // reset the pointer for (int i = 0; i < strlen(str); i++) { printf("%c\n", *p); p++; } return 0; }
Teine viis stringidega tegelemiseks on pointerite massiiv:
#include <stdio.h> int main() { char *materials[] = {"iron", "copper", "gold"}; for (int i = 0; i < 3; i++) printf("%s\n", materials[i]); return 0; }
Osutite eelised C-s
- Osutajad on kasulikud mäluasukohtadele otse juurdepääsuks.
- Need pakuvad tõhusat viisi massiivi elementidele juurdepääsuks.
- Neid kasutatakse dünaamiliseks mälu jaotamiseks ja eraldamiseks.
- Neid kasutatakse keerukate andmestruktuuride, näiteks lingitud loendite, graafikute ja puude moodustamiseks.
Osutite puudused C-s
- Osutajate mõistmine on pisut keeruline.
- Need võivad põhjustada vigu, näiteks segmenteerimisvigu või juurdepääsu soovimatule mälukohale.
- Vale kursori väärtus võib põhjustada mälu riknemist.
- Kui mälu ei vabastata, vastutavad ka pointerid mälulekete eest.
- Programmeerija kohustus on pointerit hoolikalt käsitseda.
