A pointer ( angol pointer ) egy olyan változó , amelynek értéktartománya memóriacellák címeiből vagy egy speciális érték- nulla címből áll . Ez utóbbi arra szolgál, hogy jelezze, hogy a mutató jelenleg nem hivatkozik egyik érvényes cellára sem. A mutatókat Jekaterina Logvinovna Juscsenko találta fel a címprogramozási nyelvben (1955), és nem Harold Lawson 1964-ben, ahogyan azt külföldön sokáig hitték [1] . 1955- ben az Address Programming Language bevezette a közvetett címzés és a magasabb rangú címzés fogalmát, amely lefedi a mutató fogalmát és hatókörét a modern programozási nyelvekben.
A mutatókat két területen használják:
A mutatók típusát biztosító programozási nyelvek általában két alapvető műveletet tartalmaznak: hozzárendelést és hivatkozást .
1955-ben az Address Programming Language (USSR) bevezette a „bar-operációt” (pointer dereferencing), amelyet hardverben a kijevi számítógép processzorának F-működésével valósított meg (1955) , majd később az M-20- ban. számítógépek , „ Dnepr ”, a BESM család számítógépei (BESM-2, BESM-3, BESM-3M és BESM-4), a minszki és urali családok, valamint néhány más szovjet gyártású számítógép. A mutatóhivatkozás többszörös használatát ezeken a számítógépeken a hardverben is megvalósították csoportcím-frissítési műveletekkel, hogy felgyorsítsák a faszerű formátumokkal végzett munkát (a listák és más absztrakt adattípusok a faszerű formátumok speciális esetei).
Az első valamilyen címet rendel a mutatóhoz. A második a mutató által mutatott memória érték elérésére szolgál. A hivatkozás megszüntetése lehet explicit vagy implicit; a legtöbb modern programozási nyelvben a hivatkozás megszüntetése csak akkor történik meg, ha kifejezetten meg van határozva[ mi? ] .
Példa a mutatókkal való munkára a C nyelvben :
int n = 6 ; // Egy int típusú n változó deklarálása és 6 érték hozzárendelése int * pn = malloc ( sizeof ( int ) ); // A pn mutató deklarálása és memóriafoglalás hozzá * pn = 5 ; // A mutató visszaállítása és az 5. érték hozzárendelése n = * pn ; // n hozzárendelése a pn free ( pn ) által mutatott értékhez (5 ); // Az elfoglalt memória felszabadítása pn = & n ; // Pn mutató hozzárendelése az n változó címéhez (a mutató n-re fog mutatni) n = 7 ; // *pn is egyenlő lett 7-telAz unáris operátor &a változó címét adja vissza, és az operátor a hivatkozás megszüntetésére *szolgál:
int forrásNum1 = 100 ; int forrásSzám2 = 200 ; int * pNum1 = & sourceNum1 ; int * pNum2 = & sourceNum2 ; printf ( "1-%d, 2-%d mutató értéke \n " , * pNum1 , * pNum2 ); pNum1 = pNum2 ; printf ( "1-%d, 2-%d mutató értéke \n " , * pNum1 , * pNum2 );Ha a mutató egy objektum címét tárolja, akkor azt mondják, hogy a mutató erre az objektumra hivatkozik vagy rámutat .
Azoknak a nyelveknek, amelyek biztosítják a mutatók használatát a dinamikus memóriafoglaláshoz , tartalmazniuk kell egy operátort a változók memóriabeli explicit lefoglalására. Egyes nyelvekben ezen az operátoron kívül létezik egy operátor is a változók memóriából való explicit törlésére. Mindkét művelet gyakran beépített rutinok formájában történik (a malloc és free függvények C-ben, a new és delete operátorok a C++-ban stb.). Ha egyszerű mutatót használ, nem pedig intelligens mutatót , a memóriaszivárgások elkerülése érdekében mindig törölje a változót a memóriából .
A void típusú mutató lehetővé teszi, hogy bármilyen adattípusra hivatkozzon , beleértve egy osztályt is . Ez a technológia a Boost könyvtár bármely típusának az alapja .
osztály { _ int mező ; }; AclA ; _ void * pA = ( érvénytelen * ) & clA ; // A pA mutató egy A osztályú objektumra hivatkozikA programozásban is vannak mutatók a mutatókra. Memóriacímeket tárolnak, ahol mutatók vannak arra a memóriára, ahol az adatobjektum található, vagy egy másik mutatót. Ha egy mutatót egy mutatóhoz láncolunk, amely ismét egy mutatóra mutat, lehetővé teszi számunkra, hogy bemutassuk a többszörös mutató dereferálás fogalmát (a címprogramozási nyelvben : "magasabb rangok megszólítása" ) , valamint a mutatókra vonatkozó megfelelő műveletet: többszörös indirection.
int x , * p , ** q ; x = 10 ; p = & x ; q = & p ; // pointer to pointer printf ( "%d" , ** q );A nullmutató egy olyan mutató, amely egy speciális értéket tartalmaz, jelezve, hogy az adott mutatóváltozó nem hivatkozik (nem mutat rá) egyetlen objektumra sem. A programozási nyelvekben ezt egy speciális konstans jelöli [4] :
A mutatókat nehéz kezelni. Elég könnyű rossz értéket írni egy mutatóba, ami nehezen reprodukálható hibát okozhat. Például véletlenül megváltoztatta egy mutató címét a memóriában, vagy helytelenül foglalta le a memóriát az információk számára, és itt meglepetés várhat rád: egy másik nagyon fontos változó, amelyet csak a programon belül használunk, felülíródik. A hiba pontos helyét megérteni és reprodukálni nem lesz egyszerű, az ilyen hibák kiküszöbölése pedig nem mindig triviális feladat, néha a program jelentős részét át kell írni [6] .
Néhány probléma megoldására vannak védelmi és biztosítási módszerek:
Példa egy inicializálatlan mutató hibájára:
/* a program érvénytelen. */ int main ( érvénytelen ) { int x , * p ; // Lefoglalt memória x-hez, de nem *p x = 10 -hez ; // A memória írása 10 * p = x ; // A 10 egy meghatározatlan helyre íródik a memóriában, ami a program összeomlását okozhatja. return 0 ; }Egy ilyen kis programnál a probléma észrevétlen maradhat. De amikor a program növekszik, hirtelen világossá válhat, hogy a változó más, a program számára fontos adatblokkok közé van írva. Ennek elkerülése érdekében inicializálja a [6] mutatót .
A mutató helytelen használata:
#include <stdio.h> /* a program érvénytelen */ int main ( érvénytelen ) { int x , * p ; x = 10 ; p = x ; printf ( "%d" , * p ); return 0 ; }A hívás printf()nem jeleníti хmeg a képernyőn a 10 értékét. Ehelyett valamilyen ismeretlen érték kerül kiadásra – ez a hozzárendelési operátor ( р = х;) helytelen használatának az eredménye. Ez az operátor a 10-es értéket rendeli a mutatóhoz р, amelynek a címet kell tartalmaznia, nem az értéket. Szerencsére ebben a programban a hibát észleli a fordító – figyelmeztetést ad a szokatlan mutatókonverzióról. A hiba kijavításához írja be p = &х;[6] .
A mutató helyes használataA memóriaszivárgás a számítógép szabad véletlen hozzáférésű memóriájának (RAM) mennyiségének ellenőrizetlen csökkenésének folyamata, amely a futó programok hibáihoz kapcsolódik, amelyek nem szabadítják fel időben a felesleges memóriaterületeket, vagy a rendszermemória-vezérlő szolgáltatások hibáival.
char * mutató = NULL ; int i = 0 ; for ( i = 0 ; i < 10 ; i ++ ) { pointer = ( char * ) malloc ( 100 ); // A memória 10-szer foglal le } szabad ( mutató ); // A csak az utolsó esetben szabadul felA mutatókhoz rendelt memóriacímek összehasonlíthatók. pNum1 < pNum2A és az űrlap összehasonlítása pNum1 > pNum2gyakran egy tömb elemeinek szekvenciális iterálására szolgál egy ciklusban : pNum1megfelel a memória aktuális pozíciójának és pNum2 a tömb végének. pNum1 == pNum2igazat ad vissza, ha mindkét mutató ugyanarra a memóriahelyre mutat.
A címaritmetika az assembly nyelvekből örökölt pointerek gondolatának logikus folytatásaként jelent meg: az utóbbiban lehetőség van némi eltolás jelzésére az aktuális pozíciótól.
A címaritmetika tipikus műveletei:
int * p ; // Tegyük fel, hogy p a 200 címre mutat p ++ ; // Növekedés után 200-ra mutat + sizeof(int) = 204 p -- ; // Most 200-ra mutat vissza.Egyes programozási nyelvekben vannak olyan osztályok (általában sablonok), amelyek a mutató interfészt olyan új funkciókkal valósítják meg, amelyek kijavítják a fent említett hiányosságok egy részét.
Az agy mutatószerű sejtcsoportokat használ az új információk emlékezésével kapcsolatos egyes feladatok elvégzésére [7] .
Adattípusok | |
---|---|
Értelmezhetetlen | |
Numerikus | |
Szöveg | |
Referencia | |
Összetett | |
absztrakt | |
Egyéb | |
Kapcsolódó témák |