Podmienka: Úvod do ukazovateľov
Zvážte nasledujúci program:
C
#include> int> main()> {> >int> arr[5] = { 1, 2, 3, 4, 5 };> >int> *ptr = arr;> >printf>(>'%p
'>, ptr);> >return> 0;> }> |
>
>
Vo vyššie uvedenom programe máme ukazovateľ ptr čo ukazuje na 0thprvok poľa. Podobne môžeme deklarovať aj ukazovateľ, ktorý môže ukazovať na celé pole namiesto iba jedného prvku poľa. Tento ukazovateľ je užitočný, keď hovoríme o viacrozmerných poliach.
Syntax:
data_type (* var_name ) [size_of_array];>
Tu:
- data_type je typ údajov, ktoré pole obsahuje. var_name je názov premennej ukazovateľa. size_of_array je veľkosť poľa, na ktoré bude ukazovateľ ukazovať.
Príklad
int (*ptr)[10];>
Tu ptr je ukazovateľ, ktorý môže ukazovať na pole 10 celých čísel. Keďže dolný index má vyššiu prioritu ako nepriamy, je potrebné zadať operátor smerovania a názov ukazovateľa do zátvoriek. Tu je typ ptr „ukazovateľ na pole 10 celých čísel.
Poznámka: Ukazovateľ, ktorý ukazuje na 0thprvok poľa a ukazovateľ, ktorý ukazuje na celé pole, sú úplne odlišné. Ukazuje to nasledujúci program:
C
// C program to understand difference between> // pointer to an integer and pointer to an> // array of integers.> #include> int> main()> {> >// Pointer to an integer> >int> *p;> > >// Pointer to an array of 5 integers> >int> (*ptr)[5];> >int> arr[5];> > >// Points to 0th element of the arr.> >p = arr;> > >// Points to the whole array arr.> >ptr = &arr;> > >printf>(>'p = %p, ptr = %p
'>, p, ptr);> > >p++;> >ptr++;> > >printf>(>'p = %p, ptr = %p
'>, p, ptr);> > >return> 0;> }> |
>
>Výkon
p = 0x7fff6463e890, ptr = 0x7fff6463e890 p = 0x7fff6463e894, ptr = 0x7fff6463e8a4>
Tu, p je ukazovateľ na 0thprvok poľa arr , zatiaľ čo ptr je ukazovateľ, ktorý ukazuje na celé pole arr .
- Základný typ p je int, zatiaľ čo základný typ ptr je „pole 5 celých čísel“.
- Vieme, že aritmetika ukazovateľa sa vykonáva vo vzťahu k základnej veľkosti, takže ak napíšeme ptr++, potom ukazovateľ ptr sa posunie dopredu o 20 bajtov.
Nasledujúci obrázok ukazuje ukazovateľ p a ptr. Tmavšia šípka označuje ukazovateľ na pole.
Pri dereferencovaní ukazovateľa výrazu dostaneme hodnotu, na ktorú ukazuje tento ukazovateľ. Ukazovateľ na pole ukazuje na pole, takže pri jeho dereferencovaní by sme mali dostať pole a názov poľa označuje základnú adresu. Takže vždy, keď je ukazovateľ na pole dereferencovaný, dostaneme základnú adresu poľa, na ktoré ukazuje.
C
// C program to illustrate sizes of> // pointer of array> #include> int> main()> {> >int> arr[] = { 3, 5, 6, 7, 9 };> >int> *p = arr;> >int> (*ptr)[5] = &arr;> > >printf>(>'p = %p, ptr = %p
'>, p, ptr);> >printf>(>'*p = %d, *ptr = %p
'>, *p, *ptr);> > >printf>(>'sizeof(p) = %lu, sizeof(*p) = %lu
'>,> >sizeof>(p),>sizeof>(*p));> >printf>(>'sizeof(ptr) = %lu, sizeof(*ptr) = %lu
'>,> >sizeof>(ptr),>sizeof>(*ptr));> >return> 0;> }> |
>
>Výkon
p = 0x7fff55adbff0, ptr = 0x7fff55adbff0 *p = 3, *ptr = 0x7fff55adbff0 sizeof(p) = 8, sizeof(*p) = 4 sizeof(ptr) = 8, sizeof(*ptr) = 20>
Ukazovateľ na viacrozmerné polia
1. Ukazovatele a dvojrozmerné polia
V dvojrozmernom poli môžeme pristupovať ku každému prvku pomocou dvoch dolných indexov, kde prvý dolný index predstavuje číslo riadku a druhý dolný index predstavuje číslo stĺpca. K prvkom 2-D poľa je možné pristupovať aj pomocou notácie ukazovateľa. Predpokladajme, že arr je 2-D pole, môžeme pristupovať k akémukoľvek prvku arr[i][j] poľa pomocou výrazu ukazovateľa *(*(arr + i) + j) . Teraz uvidíme, ako možno tento výraz odvodiť.
Zoberme si dvojrozmerné pole arr[3][4] :
int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };>
Keďže pamäť v počítači je organizovaná lineárne, nie je možné ukladať 2-D pole do riadkov a stĺpcov. Koncept riadkov a stĺpcov je len teoretický, v skutočnosti je 2-D pole uložené v poradí podľa riadkov, t.j. riadky sú umiestnené vedľa seba. Nasledujúci obrázok ukazuje, ako sa vyššie uvedené 2-D pole uloží do pamäte.
Každý riadok možno považovať za 1-D pole, takže dvojrozmerné pole možno považovať za kolekciu jednorozmerných polí, ktoré sú umiestnené jedno za druhým. Inými slovami, môžeme povedať, že 2-D dimenzionálne polia, ktoré sú umiestnené jeden po druhom. Takže tu arr je pole 3 prvkov, kde každý prvok je 1-D pole 4 celých čísel.
Vieme, že názov poľa je konštantný ukazovateľ, ktorý ukazuje na 0th1-D pole a obsahuje adresu 5000. Od arr je „ukazovateľ na pole 4 celých čísel“, podľa aritmetiky ukazovateľa bude výraz arr + 1 predstavovať adresu 5016 a výraz arr + 2 bude predstavovať adresu 5032.
Takže to môžeme povedať arr ukazuje na 0th1-D pole, arr + 1 poukazuje na 1sv1-D pole a arr + 2 poukazuje na 2nd1-D pole.
Vo všeobecnosti môžeme napísať:
arr + i Points to ith element of arr ->Ukazuje na to 1-D pole>
- Keďže arr + i ukazuje na ithprvok arr , pri dereferencovaní dostane ithprvok arr čo je samozrejme 1-D pole. Teda výraz *(arr + i) nám dáva základnú adresu ith1-D pole.
- Vieme, ukazovateľ ukazovateľa *(arr + i) je ekvivalentný s výrazom dolného indexu arr[i] . Takže *(arr + i) čo je rovnaké ako arr[i] nám dáva základnú adresu ith1-D pole.
- Na prístup k jednotlivému prvku nášho 2-D poľa by sme mali mať prístup k akémukoľvek jthprvok ith1-D pole.
- Keďže základný typ *(arr + i) je int a obsahuje adresu 0thprvok ith1-D poli, môžeme získať adresy nasledujúcich prvkov v ith1-D pole pridaním celočíselných hodnôt do *(arr + i) .
- Napríklad *(arr + i) + 1 bude reprezentovať adresu 1svprvok 1svprvok ith1-D pole a *(arr+i)+2 bude predstavovať adresu 2ndprvok ith1-D pole.
- Podobne *(arr + i) + j bude reprezentovať adresu jthprvok ith1-D pole. Pri dereferencovaní tohto výrazu môžeme dostať jthprvok ith1-D pole.
Ukazovatele a trojrozmerné polia
int arr[2][3][2] = { {{5, 10}, {6, 11}, {7, 12}}, {{20, 30}, {21, 31}, {22, 32}} };> V trojrozmernom poli môžeme pristupovať ku každému prvku pomocou troch dolných indexov. Zoberme si 3-D pole- Trojrozmerné pole môžeme považovať za pole 2-D poľa, t.j. každý prvok 3-D poľa sa považuje za 2-D pole. 3-D pole arr možno považovať za pole pozostávajúce z dvoch prvkov, kde každý prvok je 2-D pole. Názov poľa arr je ukazovateľ na 0th2-D pole.
Teda ukazovateľový výraz *(*(*(arr + i ) + j ) + k) je ekvivalentom dolného indexu výrazu arr[i][j][k].
Vieme, že výraz *(arr + i) je ekvivalentný arr[i] a výraz *(*(arr + i) + j) je ekvivalentný arr[i][j]. Môžeme teda povedať, že arr[i] predstavuje základnú adresu ith2-D pole a arr[i][j] predstavuje základnú adresu jth1-D pole.
Príklad
hodnota reťazca
Nižšie uvedený príklad ukazuje program na tlač prvkov 3D poľa pomocou ukazovateľov.
C
// C program to print the elements of 3-D> // array using pointer notation> #include> int> main()> {> >int> arr[2][3][2] = {> >{> >{5, 10},> >{6, 11},> >{7, 12},> >},> >{> >{20, 30},> >{21, 31},> >{22, 32},> >}> >};> >int> i, j, k;> >for> (i = 0; i <2; i++)> >{> >for> (j = 0; j <3; j++)> >{> >for> (k = 0; k <2; k++)> >printf>(>'%d '>, *(*(*(arr + i) + j) +k));> >printf>(>'
'>);> >}> >}> >return> 0;> }> |
>
>Výkon
5 10 6 11 7 12 20 30 21 31 22 32>
Nasledujúci obrázok ukazuje, ako je 3-D pole použité vo vyššie uvedenom programe uložené v pamäti.
Subscripting ukazovateľa na pole
Predpokladajme arr je 2-D pole s 3 riadkami a 4 stĺpcami a ptr je ukazovateľ na pole 4 celých čísel a ptr obsahuje základnú adresu poľa arr .
int arr[3][4] = {{10, 11, 12, 13}, {20, 21, 22, 23}, {30, 31, 32, 33}}; int (*ptr)[4]; ptr = arr;>
Od r ptr je ukazovateľ na prvý riadok 2-D poľa, t. j. pole 4 celých čísel, ptr + i bude poukazovať na ithriadok. O dereferencovaní ptr + i , dostaneme základnú adresu ithriadok. Ak chcete získať prístup k adrese jthprvok ithriadok môžeme pridať j do výrazu ukazovateľa *(ptr + i) . Takže ukazovateľový výraz *(ptr + i) + j uvádza adresu jthprvok ithriadok a výraz ukazovateľa **(*(ptr + i)+j) udáva hodnotu jthprvok ithriadok.
Vieme, že ukazovateľ ukazovateľa *(*(ptr + i) + j) je ekvivalentný výrazu dolného indexu ptr[i][j]. Takže ak máme premennú ukazovateľa obsahujúcu základnú adresu 2-D poľa, potom môžeme pristupovať k prvkom poľa dvojitým indexovaním tejto premennej ukazovateľa.
Príklad
C
// C program to print elements of a 2-D array> // by scripting a pointer to an array> #include> int> main()> {> >int> arr[3][4] = {> >{10, 11, 12, 13},> >{20, 21, 22, 23},> >{30, 31, 32, 33}> >};> >int> (*ptr)[4];> >ptr = arr;> >printf>(>'%p %p %p
'>, ptr, ptr + 1, ptr + 2);> >printf>(>'%p %p %p
'>, *ptr, *(ptr + 1), *(ptr + 2));> >printf>(>'%d %d %d
'>, **ptr, *(*(ptr + 1) + 2), *(*(ptr + 2) + 3));> >printf>(>'%d %d %d
'>, ptr[0][0], ptr[1][2], ptr[2][3]);> >return> 0;> }> |
>
>Výkon
0x7ffc9556b790 0x7ffc9556b7a0 0x7ffc9556b7b0 0x7ffc9556b790 0x7ffc9556b7a0 0x7ffc9556b7b0 10 22 33 10 22 33>