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.

  • 📌 Määratlus: Pointer hoiab teise muutuja mäluaadressi.
  • 🔧 Operators: Operaator & tagastab aadressi; operaator * tühistab sellele viitamise.
  • 🧷 Deklaratsioon: Kirjuta andmetüüp *nimi ja seejärel initsialiseeri muutuja aadressiga.
  • ???? ️ tüübid: Null-, void- ja wild-viited käituvad erinevalt ja vajavad hoolt.
  • Aritmeetika: Kursori suurendamine liigutab seda selle baastüübi suuruse võrra.
  • 🤖 AI abi: Tehisintellekti tööriistad siluvad segmenteerimisvigu ja märgistavad rippuvaid kursoreid ülevaatamise ajal.

C-keele osutid

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.

KKK

Rippuv pointer osutab vabastatud või ulatusest väljas olevale mälule. Selle vältimiseks määrake pointer kohe pärast free funktsiooni kutsumist NULL-iks ja kontrollige enne kasutamist NULL-i olemasolu.

NULL-kursori viitamine põhjustab segmenteerimisvea ja programmi jookseb käitusajal kokku. Enne *-operaatori kasutamist lugemiseks või kirjutamiseks kontrollige alati, et kursor ei oleks NULL.

Topeltkursor, mis deklareeritakse kujul int **pp, salvestab teise kursori aadressi. Seda kasutatakse dünaamiliste 2D-massiivide jaoks ja kursori argumendi muutmiseks funktsioonis.

Pointer salvestab mäluaadressi ja aadressid on antud platvormil sama laiusega, tavaliselt 4 baiti 32-bitisel ja 8 baiti 64-bitisel, olenemata tüübist, millele see osutab.

Funktsiooni osuti salvestab funktsiooni aadressi, et seda saaks dünaamiliselt kutsuda. Seda kasutatakse laialdaselt tagasihelistamiseks ja käitusajal valitud funktsioonide tabelite loomiseks.

Funktsioonid nagu malloc ja calloc tagastavad kursori mälule, mis on käitusajal heapile eraldatud. Sellele mälule pääsete ligi kursori kaudu ja vabastate selle käsuga free, et vältida lekkeid.

Jah. Tehisintellekti assistendid loevad segmenteerimisvea ja ümbritseva koodi, seejärel selgitavad tõenäolist põhjust, näiteks initsialiseerimata või vabanenud pointerit, ja pakuvad välja paranduse, mida saate üle vaadata.

Tehisintellektil põhinevad analüsaatorid koos selliste tööriistadega nagu Valgrind märgistavad mälu, mida kunagi ei vabastata, ja pointereid, mida kasutatakse pärast vabastamist. Need automatiseerivad ülevaatuse ja toovad esile riskantsed mustrid enne koodi saatmist.

Võta see postitus kokku järgmiselt: