Ukazatel ( anglicky pointer ) je proměnná, jejíž rozsah hodnot se skládá z adres paměťových buněk nebo speciální hodnoty - nulová adresa . Ten se používá k označení, že ukazatel aktuálně neodkazuje na žádnou z platných buněk. Ukazatele vynalezla Ekaterina Logvinovna Yushchenko v Address Programming Language (1955), a ne Harold Lawson v roce 1964, jak se dlouho věřilo v zahraničí [1] . V roce 1955 byly koncepty nepřímého adresování a adresování vyšších pozic zavedeny v Address Programming Language , který pokrývá koncept ukazatele a jeho rozsah v moderních programovacích jazycích.
Ukazatele se používají ve dvou oblastech:
Programovací jazyky , které poskytují typ ukazatelů, na nich zpravidla obsahují dvě základní operace: přiřazení a dereference .
V roce 1955 zavedl Address Programming Language (SSSR) „bar-operaci“ (dereferencování ukazatele), která byla hardwarově implementována F-operací procesoru v Kyjevském počítači (1955) a později v M-20. počítače , „ Dnepr “, počítače rodiny BESM (BESM-2, BESM-3, BESM-3M a BESM-4), rodiny Minsk a Ural a také některé další počítače sovětské výroby. Vícenásobné využití dereferencování ukazatelů bylo v těchto počítačích implementováno také v hardwaru pomocí operací aktualizace skupinových adres pro urychlení práce se stromovými formáty ( speciálním případem stromových formátů jsou seznamy a další abstraktní datové typy ).
První přiřadí nějakou adresu ukazateli. Druhý se používá pro přístup k hodnotě v paměti, na kterou ukazuje ukazatel. Dereferencování může být explicitní nebo implicitní; ve většině moderních programovacích jazyků dochází k dereferencování pouze tehdy, je-li výslovně uvedeno[ co? ] .
Příklad práce s ukazateli v jazyce C :
int n = 6 ; // Deklarování proměnné n typu int a přiřazení jí hodnoty 6 int * pn = malloc ( sizeof ( int ) ); // Deklarace ukazatele pn a přidělení paměti pro něj * pn = 5 ; // Dereference pointer a přiřazení hodnoty 5 n = * pn ; // Přiřaďte n hodnotě (5), na kterou ukazuje pn free ( pn ); // Uvolní obsazenou paměť pn = & n ; // Přiřadí ukazatel pn k adrese proměnné n (ukazatel bude ukazovat na n) n = 7 ; // *pn se také stalo rovno 7Unární operátor &vrací adresu proměnné a operátor *se používá k dereferenci:
int sourceNum1 = 100 ; int sourceNum2 = 200 ; int * pNum1 = & sourceNum1 ; int * pNum2 = & sourceNum2 ; printf ( "Hodnota ukazatele 1-%d, 2-%d \n " , * pNum1 , * pNum2 ); pNum1 = pNum2 ; printf ( "Hodnota ukazatele 1-%d, 2-%d \n " , * pNum1 , * pNum2 );Pokud ukazatel ukládá adresu nějakého objektu, pak se říká, že ukazatel odkazuje nebo ukazuje na tento objekt.
Jazyky, které umožňují použití ukazatelů pro dynamickou alokaci paměti , musí obsahovat operátor pro explicitní alokaci proměnných v paměti. V některých jazycích je kromě tohoto operátoru ještě operátor pro explicitní mazání proměnných z paměti. Obě tyto operace mají často podobu vestavěných rutin (funkce malloc a free v C, operátory new a delete v C++ a tak dále). Při použití jednoduchého ukazatele namísto inteligentního ukazatele byste měli vždy včas odstranit proměnnou z paměti, abyste se vyhnuli úniku paměti .
Ukazatel typu void vám umožňuje odkazovat na jakýkoli datový typ , včetně třídy . Tato technologie je základem jakéhokoli typu knihovny Boost .
třída A { int pole ; }; AclA ; _ void * pA = ( void * ) & clA ; // ukazatel pA odkazuje na objekt třídy AV programování jsou také ukazatele na ukazatele. Ukládají adresy paměti, kde jsou ukazatele na paměť, kde se nachází datový objekt, nebo jiný ukazatel. Zřetězení ukazatele na ukazatel, který opět ukazuje na ukazatel, nám umožňuje zavést koncept dereferencování více ukazatelů (v jazyce Address Programming Language : „adresování vyšších úrovní“ ) a odpovídající akci s ukazateli: Vícenásobné indirection.
int x , * p , ** q ; x = 10 ; p = & x ; q = & p ; // ukazatel na ukazatel printf ( "%d" , ** q );Nulový ukazatel je ukazatel, který má speciální hodnotu, která označuje, že daná proměnná ukazatele neodkazuje (neukazuje na) žádný objekt. V programovacích jazycích je reprezentován speciální konstantou [4] :
Ukazatele se těžko ovládají. Je dost snadné zapsat špatnou hodnotu do ukazatele, což může způsobit těžko reprodukovatelnou chybu. Například jste omylem změnili adresu ukazatele v paměti nebo nesprávně alokovali paměť pro informace a zde na vás může čekat překvapení: dojde k přepsání další velmi důležité proměnné, která se používá pouze uvnitř programu. Pochopit, kde přesně je chyba a reprodukovat ji, nebude snadné a odstranění takových chyb není vždy triviální úkol, někdy musíte přepsat významnou část programu [6] .
K vyřešení některých problémů existují metody ochrany a pojištění:
Příklad chyby s neinicializovaným ukazatelem:
/* program je neplatný. */ int main ( void ) { int x , * p ; // Alokovaná paměť pro x, ale ne pro *p x = 10 ; // Paměť se zapisuje 10 * p = x ; // 10 je zapsáno na nedefinované místo v paměti, což může způsobit selhání programu. návrat 0 ; }V tak malém programu může problém zůstat bez povšimnutí. Ale když se program rozroste, může být náhle jasné, že proměnná je zapsána mezi jiné datové bloky, které jsou pro program důležité. Chcete-li se této situaci vyhnout, stačí inicializovat ukazatel [6] .
Nesprávné použití ukazatele:
#include <stdio.h> /* program je neplatný */ int main ( void ) { int x , * p ; x = 10 ; p = x ; printf ( "%d" , * p ); návrat 0 ; }Volání printf()nezobrazuje na obrazovce hodnotu х, která je 10. Místo toho je na výstupu nějaká neznámá hodnota – je to výsledek nesprávného použití operátoru přiřazení ( р = х;). Tento operátor přiřadí hodnotu 10 ukazateli р, který by měl obsahovat adresu, nikoli hodnotu. Naštěstí chybu v tomto programu detekuje kompilátor – vydá varování o neobvyklé konverzi ukazatele. Pro opravu chyby napište p = &х;[6] .
Správné použití ukazateleÚnik paměti je proces nekontrolovaného snižování množství volné paměti RAM (random-access Memory) počítače spojený s chybami ve spuštěných programech, které neuvolňují nepotřebné oblasti paměti včas, nebo s chybami ve službách řízení systémové paměti.
char * ukazatel = NULL ; int i = 0 ; pro ( i = 0 ; i < 10 ; i ++ ) { ukazatel = ( char * ) malloc ( 100 ); // Paměť alokuje 10krát } zdarma ( ukazatel ); // A se uvolní pouze v posledním případěAdresy paměti přiřazené ukazatelům lze porovnávat. Porovnání formuláře pNum1 < pNum2a pNum1 > pNum2se často používají k postupnému iterování prvků pole ve smyčce : pNum1odpovídá aktuální pozici v paměti a odpovídá pNum2 konci pole. pNum1 == pNum2vrátí hodnotu true, pokud oba ukazatele ukazují na stejné místo v paměti.
Aritmetika adres se objevila jako logické pokračování myšlenky ukazatelů zděděných z jazyků symbolických instrukcí: v posledně jmenovaných je možné označit určitý posun od aktuální pozice.
Typické operace aritmetiky adres:
int * p ; // Řekněme, že p ukazuje na adresu 200 p ++ ; // Po inkrementaci ukazuje na 200 + sizeof(int) = 204 p -- ; // Nyní ukazuje zpět na 200.V některých programovacích jazycích existují třídy (obvykle šablony), které implementují rozhraní ukazatele s novou funkčností, která opravuje některé z výše uvedených nedostatků.
Mozek používá skupiny buněk podobné ukazateli k provádění některých úkolů spojených se zapamatováním nových informací [7] .
Typy dat | |
---|---|
Neinterpretovatelné | |
Numerický | |
Text | |
Odkaz | |
Kompozitní | |
abstraktní | |
jiný | |
související témata |