Kazalci so simbolične predstavitve naslovov. Programom omogočajo simulacijo klica po sklicu ter ustvarjanje in upravljanje dinamičnih podatkovnih struktur. Ponavljanje po elementih v nizih ali drugih podatkovnih strukturah je ena od glavnih uporab kazalcev.
Naslov spremenljivke, s katero delate, je dodeljen spremenljivki kazalca, ki kaže na isto vrsto podatkov (na primer int ali niz).
rr algoritem
Sintaksa:
datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
Kako uporabljati kazalec?
- Definirajte spremenljivko kazalca
- Dodeljevanje naslova spremenljivke kazalcu z unarnim operatorjem (&), ki vrne naslov te spremenljivke.
- Dostop do vrednosti, shranjene v naslovu, z unarnim operatorjem (*), ki vrne vrednost spremenljivke, ki se nahaja na naslovu, ki ga določa njen operand.
Razlog, da podatkovni tip povežemo s kazalcem, je da ve, v koliko bajtih so shranjeni podatki . Ko povečamo kazalec, povečamo kazalec za velikost podatkovnega tipa, na katerega kaže.
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; }> Izhod
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>
Reference in kazalci
Obstajajo 3 načini za posredovanje argumentov C++ funkciji:
- Klic po vrednosti
- Klic po sklicu z argumentom kazalca
- Klic po sklicu z referenčnim argumentom
// 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(); }> Izhod
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++ se argumenti privzeto posredujejo po vrednosti in spremembe v klicani funkciji se ne bodo odražale v posredovani spremenljivki. Spremembe se spremenijo v klon, ki ga naredi klicana funkcija. Če želimo neposredno spremeniti izvirno kopijo (zlasti pri podajanju velikega predmeta ali niza) in/ali se izogniti dodatnim stroškim kloniranja, uporabimo prenos po sklicu. Prenos po sklicu z referenčnimi argumenti ne zahteva nobene okorne sintakse za sklicevanje in dereferenciranje.
- Kazalci funkcij v C
- Kazalec na funkcijo
Ime matrike kot kazalci
An niz ime vsebuje naslov prvega elementa matrike, ki deluje kot stalni kazalec. To pomeni, da naslova, shranjenega v imenu polja, ni mogoče spremeniti. Na primer, če imamo matriko z imenom val, potem val in &val[0] se lahko uporabljata zamenljivo.
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(); }> Izhod
Elements of the array are: 5 10 20>
Če je kazalec ptr poslan funkciji kot argument, je mogoče do matrike val dostopati na podoben način. Kazalec proti nizu
Izrazi kazalca in aritmetika kazalca
Omejen nabor aritmetika operacije se lahko izvajajo na kazalcih, ki so:
vrstni red po naključnem sql
- povečano ( ++ )
- zmanjšano ( — )
- kazalcu se lahko doda celo število ( + ali += )
- celo število se lahko odšteje od kazalca ( – ali -= )
- razlika med dvema kazalcema (p1-p2)
( Opomba: Aritmetika kazalca je nesmiselna, razen če se izvaja na matriki.)
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(); }> Izhod
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
Napredni zapis kazalca
Razmislite o zapisu kazalca za dvodimenzionalne številske nize. upoštevajte naslednjo izjavo
int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>Na splošno je nums[ i ][ j ] enakovreden *(*(nums+i)+j)
Kazalci in literali nizov
Nizovni literali so nizi, ki vsebujejo zaporedja znakov, zaključena z ničlo. Nizovni literali so nizi znakovnega tipa in zaključnega ničelnega znaka, pri čemer je vsak od elementov tipa const char (ker znakov niza ni mogoče spreminjati).
>
To razglasi matriko z dobesedno predstavitvijo za geek, nato pa je kazalec na njen prvi element dodeljen ptr. Če si predstavljamo, da je geek shranjen na pomnilniških lokacijah, ki se začnejo na naslovu 1800, lahko prejšnjo deklaracijo predstavimo kot:

Ker se kazalci in nizi v izrazih obnašajo na enak način, lahko ptr uporabite za dostop do znakov nizovnega literala. Na primer:
char ptr = 0; char x = *(ptr+3); char y = ptr[3];>
Tu x in y vsebujeta k, shranjen pri 1803 (1800+3).
Kazalci na kazalce
V C++ lahko ustvarimo kazalec na kazalec, ki lahko kaže na podatke ali drug kazalec. Sintaksa preprosto zahteva unarni operator (*) za vsako raven posrednosti med deklariranjem kazalca.
char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>
Tukaj b kaže na char, ki shranjuje 'g' in c kaže na kazalec b.
java izboljšana zanka
Kazalci praznine
To je posebna vrsta kazalca, ki je na voljo v C++ in predstavlja odsotnost vrste. Kazalci praznine so kazalci, ki kažejo na vrednost, ki nima tipa (in s tem tudi nedoločene dolžine in nedoločenih dereferencirnih lastnosti). To pomeni, da imajo void kazalci veliko prilagodljivost, saj lahko kažejo na katero koli vrsto podatkov. Za to prilagodljivost obstaja izplačilo. Teh kazalcev ni mogoče neposredno dereferencirati. Najprej jih je treba pretvoriti v drug tip kazalca, ki kaže na konkreten podatkovni tip, preden se dereferencirajo.
zgornji ukaz unixC++
// 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(); }> Izhod
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>
Neveljavni kazalci
Kazalec mora kazati na veljaven naslov, vendar ne nujno na veljavne elemente (kot pri nizih). Ti se imenujejo neveljavni kazalci. Neinicializirani kazalci so tudi neveljavni kazalci.
int *ptr1; int arr[10]; int *ptr2 = arr+20;>
Tukaj je ptr1 neinicializiran, tako da postane neveljaven kazalec, ptr2 pa je izven meja arr, zato tudi postane neveljaven kazalec. (Opomba: neveljavni kazalci ne povzročijo nujno napak pri prevajanju)
NULL kazalci
A ničelni kazalec je kazalec, ki ne kaže nikamor in ne samo na neveljaven naslov. Sledita 2 metoda za dodelitev kazalca kot NULL;
int *ptr1 = 0; int *ptr2 = NULL;>
Prednosti kazalcev
- Kazalci zmanjšajo kodo in izboljšajo zmogljivost. Uporabljajo se za pridobivanje nizov, dreves, nizov, struktur in funkcij.
- Kazalci nam omogočajo vrnitev več vrednosti iz funkcij.
- Poleg tega nam kazalci omogočajo dostop do pomnilniške lokacije v pomnilniku računalnika.
Povezani članki:
- Neprozoren kazalec
- Kazalci blizu, daleč in veliki
kvizi:
- Osnove kazalca
- Napredni kazalec