Jak wiemy, wskaźnik służy do przechowywania adresu zmiennej w języku C. Wskaźnik skraca czas dostępu do zmiennej. Jednak w C możemy również zdefiniować wskaźnik do przechowywania adresu innego wskaźnika. Taki wskaźnik nazywany jest wskaźnikiem podwójnym (wskaźnik do wskaźnika). Pierwszy wskaźnik służy do przechowywania adresu zmiennej, podczas gdy drugi wskaźnik służy do przechowywania adresu pierwszego wskaźnika. Rozumiemy to na podstawie schematu podanego poniżej.
Poniżej podana jest składnia deklarowania podwójnego wskaźnika.
int **p; // pointer to a pointer which is pointing to an integer.
Rozważ następujący przykład.
#include void main () { int a = 10; int *p; int **pp; p = &a; // pointer p is pointing to the address of a pp = &p; // pointer pp is a double pointer pointing to the address of pointer p printf('address of a: %x ',p); // Address of a will be printed printf('address of p: %x ',pp); // Address of p will be printed printf('value stored at p: %d ',*p); // value stoted at the address contained by p i.e. 10 will be printed printf('value stored at pp: %d ',**pp); // value stored at the address contained by the pointer stoyred at pp }
Wyjście
address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10
Przykład podwójnego wskaźnika C
Zobaczmy przykład, w którym jeden wskaźnik wskazuje adres innego wskaźnika.
Jak widać na powyższym rysunku, p2 zawiera adres p (fff2), a p zawiera adres zmiennej liczbowej (fff4).
#include int main(){ int number=50; int *p;//pointer to int int **p2;//pointer to pointer p=&number;//stores the address of number variable p2=&p; printf('Address of number variable is %x ',&number); printf('Address of p variable is %x ',p); printf('Value of *p variable is %d ',*p); printf('Address of p2 variable is %x ',p2); printf('Value of **p2 variable is %d ',*p); return 0; }
Wyjście
Address of number variable is fff4 Address of p variable is fff4 Value of *p variable is 50 Address of p2 variable is fff2 Value of **p variable is 50
P. Jaki będzie wynik poniższego programu?
#include void main () { int a[10] = {100, 206, 300, 409, 509, 601}; //Line 1 int *p[] = {a, a+1, a+2, a+3, a+4, a+5}; //Line 2 int **pp = p; //Line 3 pp++; // Line 4 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 5 *pp++; // Line 6 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 7 ++*pp; // Line 8 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 9 ++**pp; // Line 10 printf('%d %d %d ',pp-p,*pp - a,**pp); // Line 11 }
Wyjaśnienie
W powyższym pytaniu arytmetyka wskaźników jest używana z podwójnym wskaźnikiem. Zdefiniowana jest tablica złożona z 6 elementów, na którą wskazuje tablica wskaźników p. Tablicę wskaźników p wskazuje podwójny wskaźnik pp. Powyższy obrazek daje jednak krótkie wyobrażenie o tym, w jaki sposób pamięć jest alokowana do tablicy a i tablicy wskaźników p. Elementy p to wskaźniki wskazujące na każdy element tablicy a. Ponieważ wiemy, że nazwa tablicy zawiera adres podstawowy tablicy, będzie ona działać jako wskaźnik i czy wartość będzie można przechodzić za pomocą *(a), *(a+1) itd. Jak pokazano na obrazku , a[0] można uzyskać w następujący sposób.
jak wyjść z pętli while Java
- a[0]: jest to najprostszy sposób uzyskania dostępu do pierwszego elementu tablicy
- *(a): ponieważ a przechowuje adres pierwszego elementu tablicy, możemy uzyskać dostęp do jego wartości za pomocą wskaźnika pośredniego.
- *p[0]: jeśli dostęp do a[0] ma być uzyskany poprzez użycie wskaźnika p do niego, wówczas możemy użyć operatora pośredniego (*) na pierwszym elemencie tablicy wskaźników p, tj. *p[0].
- **(pp): ponieważ pp przechowuje adres bazowy tablicy wskaźników, *pp poda wartość pierwszego elementu tablicy wskaźników, która jest adresem pierwszego elementu tablicy liczb całkowitych. **p da rzeczywistą wartość pierwszego elementu tablicy liczb całkowitych.
Wracając do programu, linie 1 i 2 deklarują względnie tablicę liczb całkowitych i wskaźników. Linia 3 inicjuje podwójny wskaźnik do tablicy wskaźników p. Jak pokazano na obrazku, jeśli adres tablicy zaczyna się od 200, a rozmiar liczby całkowitej wynosi 2, to tablica wskaźników będzie zawierać wartości 200, 202, 204, 206, 208, 210. Rozważmy, że adres bazowy tablicy wskaźników to 300; podwójny wskaźnik pp zawiera adres tablicy wskaźników, tj. 300. Linia nr 4 zwiększa wartość pp o 1, tj. pp będzie teraz wskazywać adres 302.
Linia numer 5 zawiera wyrażenie, które wypisuje trzy wartości, tj. pp - p, *pp - a, **pp. Obliczmy je każdy z nich.
- pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, czyli wydrukowane zostanie 1.
- pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, czyli wydrukowana zostanie 1.
- pp = 302, *pp = 202, *(*pp) = 206, czyli zostanie wydrukowane 206.
Dlatego w wyniku linii 5 na konsoli zostaną wydrukowane dane wyjściowe 1, 1, 206. W linii 6 zapisano *pp++. Tutaj musimy zauważyć, że dwa operatory jednoargumentowe * i ++ będą miały ten sam priorytet. Dlatego zgodnie z zasadą skojarzenia będzie on oceniany od prawej do lewej. Dlatego wyrażenie *pp++ można przepisać jako (*(pp++)). Ponieważ pp = 302, co teraz będzie wynosić 304. *pp da 204.
W linii 7 ponownie zapisywane jest wyrażenie, które wypisuje trzy wartości, tj. pp-p, *pp-a, *pp. Obliczmy każdy z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, czyli wydrukowane zostaną 2.
- pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, czyli wydrukowane zostaną 2.
- pp = 304, *pp = 204, *(*pp) = 300, czyli wydrukowane zostanie 300.
Dlatego w wyniku linii 7 na konsoli zostaną wydrukowane dane wyjściowe 2, 2, 300. W linii 8 zapisano +***pp. Zgodnie z zasadą skojarzeń można to zapisać jako (++(*(pp))). Ponieważ pp = 304, *pp = 204, wartość *pp = *(p[2]) = 206, która będzie teraz wskazywała na a[3].
W linii 9 ponownie zapisywane jest wyrażenie, które wypisuje trzy wartości, tj. pp-p, *pp-a, *pp. Obliczmy każdy z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, czyli wydrukowane zostaną 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, czyli wydrukowane zostanie 3.
- pp = 304, *pp = 206, *(*pp) = 409, czyli zostanie wydrukowane 409.
Dlatego w wyniku linii 9 na konsoli zostaną wydrukowane dane wyjściowe 2, 3, 409. W linii 10 zapisano ++**pp. zgodnie z zasadą łączności można to zapisać jako (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. Innymi słowy, a[3] = 410.
W linii 11 ponownie zapisywane jest wyrażenie, które wypisuje trzy wartości, tj. pp-p, *pp-a, *pp. Obliczmy każdy z nich.
- pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, czyli wydrukowane zostaną 2.
- pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, czyli wydrukowane zostanie 3.
- W linii 8, **pp = 410.
Dlatego w wyniku linii 9 na konsoli zostaną wydrukowane dane wyjściowe 2, 3, 410.
Ostatecznie wynik pełnego programu zostanie podany jako:
Zmienna zmienna Java
Wyjście
1 1 206 2 2 300 2 3 409 2 3 410