Ukazatele jsou symbolické reprezentace adres. Umožňují programům simulovat volání po referenci a také vytvářet a manipulovat s dynamickými datovými strukturami. Iterace přes prvky v polích nebo jiných datových strukturách je jedním z hlavních použití ukazatelů.
Adresa proměnné, se kterou pracujete, je přiřazena proměnné ukazatele, která ukazuje na stejný datový typ (jako je int nebo řetězec).
řetězec v poli v c
Syntax:
datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
Jak používat ukazatel?
- Definujte proměnnou ukazatele
- Přiřazení adresy proměnné ukazateli pomocí unárního operátoru (&), který vrací adresu dané proměnné.
- Přístup k hodnotě uložené v adrese pomocí unárního operátoru (*), který vrací hodnotu proměnné umístěné na adrese určené jejím operandem.
Důvod, proč spojujeme datový typ s ukazatelem, je že ví, v kolika bajtech jsou data uložena . Když inkrementujeme ukazatel, zvětšíme ukazatel o velikost datového typu, na který ukazuje.
C++ // C++ program to illustrate Pointers #include using namespace std; void geeks() { int var = 20; // declare pointer variable int* ptr; // note that data type of ptr and var must be same ptr = &var; // assign the address of a variable to a pointer cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at var = ' << var << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; } // Driver program int main() { geeks(); return 0; }> Výstup
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>
Reference a ukazatele
Existují 3 způsoby, jak předat argumenty C++ funkci:
- Call-By-Value
- Call-by-Reference s argumentem ukazatele
- Call-by-Reference s argumentem reference
// C++ program to illustrate call-by-methods #include using namespace std; // Pass-by-Value int square1(int n) { // Address of n in square1() is not the same as n1 in // main() cout << 'address of n1 in square1(): ' << &n << '
'; // clone modified inside the function n *= n; return n; } // Pass-by-Reference with Pointer Arguments void square2(int* n) { // Address of n in square2() is the same as n2 in main() cout << 'address of n2 in square2(): ' << n << '
'; // Explicit de-referencing to get the value pointed-to *n *= *n; } // Pass-by-Reference with Reference Arguments void square3(int& n) { // Address of n in square3() is the same as n3 in main() cout << 'address of n3 in square3(): ' << &n << '
'; // Implicit de-referencing (without '*') n *= n; } void geeks() { // Call-by-Value int n1 = 8; cout << 'address of n1 in main(): ' << &n1 << '
'; cout << 'Square of n1: ' << square1(n1) << '
'; cout << 'No change in n1: ' << n1 << '
'; // Call-by-Reference with Pointer Arguments int n2 = 8; cout << 'address of n2 in main(): ' << &n2 << '
'; square2(&n2); cout << 'Square of n2: ' << n2 << '
'; cout << 'Change reflected in n2: ' << n2 << '
'; // Call-by-Reference with Reference Arguments int n3 = 8; cout << 'address of n3 in main(): ' << &n3 << '
'; square3(n3); cout << 'Square of n3: ' << n3 << '
'; cout << 'Change reflected in n3: ' << n3 << '
'; } // Driver program int main() { geeks(); }> Výstup
address of n1 in main(): 0x7fffa7e2de64 address of n1 in square1(): 0x7fffa7e2de4c Square of n1: 64 No change in n1: 8 address of n2 in main(): 0x7fffa7e2de68 address of n2 in square2(): 0x7fffa7e2de68 Square of n2: 64 Change reflected in n2: 64 address of n3 in main(): 0x7fffa7e2de6c address of n3 in square3(): 0x7fffa7e2de6c Square of n3: 64 Change reflected in n3: 64>
V C++ jsou ve výchozím nastavení argumenty předávány hodnotou a změny provedené ve volané funkci se v předané proměnné neprojeví. Změny jsou provedeny do klonu provedeného volanou funkcí. Pokud si přejete upravit původní kopii přímo (zejména při předávání velkého objektu nebo pole) a/nebo se vyhnout režii klonování, používáme pass-by-reference. Pass-by-Reference s referenčními argumenty nevyžaduje žádnou neohrabanou syntaxi pro odkazování a dereferencování.
- Funkční ukazatele v C
- Ukazatel na funkci
Název pole jako ukazatele
An pole name obsahuje adresu prvního prvku pole, který funguje jako konstantní ukazatel. To znamená, že adresu uloženou v názvu pole nelze změnit. Například, pokud máme pole s názvem val then val a &val[0] lze použít zaměnitelně.
C++ // C++ program to illustrate Array Name as Pointers #include using namespace std; void geeks() { // Declare an array int val[3] = { 5, 10, 20 }; // declare pointer variable int* ptr; // Assign the address of val[0] to ptr // We can use ptr=&val[0];(both are same) ptr = val; cout << 'Elements of the array are: '; cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2]; } // Driver program int main() { geeks(); }> Výstup
Elements of the array are: 5 10 20>
Pokud je ukazatel ptr odeslán funkci jako argument, lze k poli val přistupovat podobným způsobem. Ukazatel vs pole
Výrazy ukazatele a aritmetika ukazatele
Omezená sada aritmetický operace lze provádět na ukazatelích, které jsou:
- zvýšen (++)
- sníženo ( — )
- k ukazateli lze přidat celé číslo ( + nebo += )
- celé číslo lze odečíst od ukazatele ( – nebo -= )
- rozdíl mezi dvěma ukazateli (p1-p2)
( Poznámka: Aritmetika ukazatele nemá smysl, pokud není provedena na poli.)
C++ // C++ program to illustrate Pointer Arithmetic #include using namespace std; void geeks() { // Declare an array int v[3] = { 10, 100, 200 }; // declare pointer variable int* ptr; // Assign the address of v[0] to ptr ptr = v; for (int i = 0; i < 3; i++) { cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; // Increment pointer ptr by 1 ptr++; } } // Driver program int main() { geeks(); }> Výstup
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
Pokročilá notace ukazatele
Zvažte notaci ukazatele pro dvourozměrná číselná pole. zvažte následující prohlášení
int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>Obecně platí, že nums[ i ][ j ] je ekvivalentní *(*(nums+i)+j)
java výjimky
Ukazatele a řetězcové literály
Řetězcové literály jsou pole obsahující sekvence znaků ukončené nulou. Řetězcové literály jsou pole typu znak plus ukončovací znak null, přičemž každý z prvků je typu const char (protože znaky řetězce nelze upravit).
>
Toto deklaruje pole s doslovnou reprezentací pro geek a pak je ukazatel na jeho první prvek přiřazen k ptr. Pokud si představíme, že geek je uložen na paměťových místech začínajících na adrese 1800, můžeme předchozí deklaraci reprezentovat jako:
jak předělat ve photoshopu

Protože se ukazatele a pole chovají ve výrazech stejným způsobem, lze ptr použít k přístupu ke znakům řetězcového literálu. Například:
char ptr = 0; char x = *(ptr+3); char y = ptr[3];>
Zde jak x, tak y obsahují k uložené na 1803 (1800+3).
Ukazatele na ukazatele
V C++ můžeme vytvořit ukazatel na ukazatel, který zase může ukazovat na data nebo jiný ukazatel. Syntaxe jednoduše vyžaduje unární operátor (*) pro každou úroveň nepřímosti při deklaraci ukazatele.
char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>
Zde b ukazuje na znak, který ukládá „g“ a c ukazuje na ukazatel b.
Prázdné ukazatele
Jedná se o speciální typ ukazatele dostupný v C++, který představuje absenci typu. Prázdné ukazatele jsou ukazatele, které ukazují na hodnotu, která nemá žádný typ (a tedy také neurčitou délku a neurčité dereferenční vlastnosti). To znamená, že void ukazatele mají velkou flexibilitu, protože mohou ukazovat na jakýkoli datový typ. Tato flexibilita se vyplatí. Tyto ukazatele nelze přímo dereferencovat. Musí být nejprve transformovány na nějaký jiný typ ukazatele, který ukazuje na konkrétní datový typ, než budou dereferencovány.
C++ // C++ program to illustrate Void Pointer #include using namespace std; void increase(void* data, int ptrsize) { if (ptrsize == sizeof(char)) { char* ptrchar; // Typecast data to a char pointer ptrchar = (char*)data; // Increase the char stored at *ptrchar by 1 (*ptrchar)++; cout << '*data points to a char' << '
'; } else if (ptrsize == sizeof(int)) { int* ptrint; // Typecast data to a int pointer ptrint = (int*)data; // Increase the int stored at *ptrchar by 1 (*ptrint)++; cout << '*data points to an int' << '
'; } } void geek() { // Declare a character char c = 'x'; // Declare an integer int i = 10; // Call increase function using a char and int address // respectively increase(&c, sizeof(c)); cout << 'The new value of c is: ' << c << '
'; increase(&i, sizeof(i)); cout << 'The new value of i is: ' << i << '
'; } // Driver program int main() { geek(); }> Výstup
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>
Neplatné ukazatele
Ukazatel by měl ukazovat na platnou adresu, ale ne nutně na platné prvky (jako u polí). Říká se jim neplatné ukazatele. Neinicializované ukazatele jsou také neplatné ukazatele.
mylivecricket.in
int *ptr1; int arr[10]; int *ptr2 = arr+20;>
Zde je ptr1 neinicializovaný, takže se stane neplatným ukazatelem a ptr2 je mimo meze arr, takže se také stane neplatným ukazatelem. (Poznámka: neplatné ukazatele nemusí nutně způsobit chyby kompilace)
NULL ukazatele
A nulový ukazatel je ukazatel, který nikam neukazuje, a nejen neplatná adresa. Následují 2 způsoby přiřazení ukazatele jako NULL;
int *ptr1 = 0; int *ptr2 = NULL;>
Výhody ukazatelů
- Ukazatele snižují kód a zlepšují výkon. Používají se k načítání řetězců, stromů, polí, struktur a funkcí.
- Ukazatele nám umožňují vracet více hodnot z funkcí.
- Kromě toho nám ukazatele umožňují přístup k umístění paměti v paměti počítače.
Související články:
- Neprůhledný ukazatel
- Blízké, vzdálené a obrovské ukazatele
kvízy:
- Základy ukazatele
- Pokročilý ukazatel