logo

C двоен показалец (показател към показалец)

Както знаем, указателят се използва за съхраняване на адреса на променлива в C. Указателят намалява времето за достъп на променлива. В C обаче можем също да дефинираме указател за съхраняване на адреса на друг указател. Такъв указател е известен като двоен указател (указател към указател). Първият указател се използва за съхраняване на адреса на променлива, докато вторият указател се използва за съхраняване на адреса на първия указател. Нека го разберем от диаграмата, дадена по-долу.

показалец към показалец в c

Синтаксисът за деклариране на двоен указател е даден по-долу.

как да избирате колони от различни таблици в sql
 int **p; // pointer to a pointer which is pointing to an integer. 

Помислете за следния пример.

 #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 } 

Изход

 address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10 

C пример с двоен указател

Нека видим пример, при който един указател сочи към адреса на друг указател.

C пример от указател към указател

Както можете да видите на фигурата по-горе, p2 съдържа адреса на p (fff2), а p съдържа адреса на числовата променлива (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; } 

Изход

 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 

В. Какъв ще бъде резултатът от следната програма?

 #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 } 

Обяснение

Въпрос с двоен указател

В горния въпрос аритметиката на показалеца се използва с двойния показалец. Дефинира се масив от 6 елемента, който се сочи от масив от указател p. Масивът на указателя p е насочен от двоен указател pp. Горното изображение обаче ви дава кратка представа за това как се разпределя паметта към масива a и масива указател p. Елементите на p са указателите, които сочат към всеки елемент от масива a. Тъй като знаем, че името на масива съдържа основния адрес на масива, следователно, то ще работи като указател и може ли стойността да бъде обходена с помощта на *(a), *(a+1) и т.н. Както е показано на изображението , a[0] може да бъде достъпен по следните начини.

  • a[0]: това е най-простият начин за достъп до първия елемент на масива
  • *(a): тъй като съхранява адреса на първия елемент от масива, можем да получим достъп до неговата стойност, като използваме индиректен указател върху него.
  • *p[0]: ако a[0] трябва да бъде достъпен чрез използване на указател p към него, тогава можем да използваме индиректен оператор (*) на първия елемент от масива на указателя p, т.е. *p[0].
  • **(pp): тъй като pp съхранява основния адрес на масива от указатели, *pp ще даде стойността на първия елемент от масива от указатели, който е адресът на първия елемент от масива с цели числа. **p ще даде действителната стойност на първия елемент от целочисления масив.

Стигайки до програмата, ред 1 и 2 декларират относително цялото число и масива на указателя. Ред 3 инициализира двойния указател към масива от указатели p. Както е показано на изображението, ако адресът на масива започва от 200 и размерът на цялото число е 2, тогава масивът на указателя ще съдържа стойностите като 200, 202, 204, 206, 208, 210. Нека приемем, че базовият адрес на масива от указатели е 300; двойният указател pp съдържа адреса на масива от указатели, т.е. 300. Ред номер 4 увеличава стойността на pp с 1, т.е. сега pp ще сочи към адрес 302.

Ред номер 5 съдържа израз, който отпечатва три стойности, т.е. pp - p, *pp - a, **pp. Нека ги изчислим всеки един от тях.

execlp
  • pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, т.е. ще бъде отпечатано 1.
  • pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, т.е. ще бъде отпечатано 1.
  • pp = 302, *pp = 202, *(*pp) = 206, т.е. 206 ще бъдат отпечатани.

Следователно като резултат от ред 5, изходът 1, 1, 206 ще бъде отпечатан на конзолата. На ред 6 е написано *pp++. Тук трябва да забележим, че два унарни оператора * и ++ ще имат еднакъв приоритет. Следователно, по правилото на асоциативността, ще се оценява отдясно наляво. Следователно изразът *pp++ може да бъде пренаписан като (*(pp++)). Тъй като pp = 302, което сега ще стане 304. *pp ще даде 204.

На ред 7 отново е написан изразът, който отпечатва три стойности, т.е. pp-p, *pp-a, *pp. Нека изчислим всеки един от тях.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, т.е. 2 ще бъдат отпечатани.
  • pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, т.е. ще бъде отпечатано 2.
  • pp = 304, *pp = 204, *(*pp) = 300, т.е. 300 ще бъдат отпечатани.

Следователно, като резултат от ред 7, изходът 2, 2, 300 ще бъде отпечатан на конзолата. На ред 8 е написано +*pp. Съгласно правилото за асоциативност това може да се пренапише като (++(*(pp))). Тъй като pp = 304, *pp = 204, стойността на *pp = *(p[2]) = 206, която сега ще сочи към a[3].

колко града има в Съединените американски щати

На ред 9 отново е написан изразът, който отпечатва три стойности, т.е. pp-p, *pp-a, *pp. Нека изчислим всеки един от тях.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, т.е. 2 ще бъдат отпечатани.
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, т.е. ще бъдат отпечатани 3.
  • pp = 304, *pp = 206, *(*pp) = 409, т.е. 409 ще бъдат отпечатани.

Следователно, като резултат от ред 9, изходът 2, 3, 409 ще бъде отпечатан на конзолата. На ред 10 е написано ++**pp. според правилото за асоциативност това може да се пренапише като (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. С други думи, a[3] = 410.

На ред 11 отново е написан изразът, който отпечатва три стойности, т.е. pp-p, *pp-a, *pp. Нека изчислим всеки един от тях.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, т.е. 2 ще бъдат отпечатани.
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, т.е. ще бъдат отпечатани 3.
  • На ред 8, **pp = 410.

Следователно като резултат от ред 9, изходът 2, 3, 410 ще бъде отпечатан на конзолата.

java инициализира масив

Най-накрая изходът от пълната програма ще бъде даден като:

Изход

 1 1 206 2 2 300 2 3 409 2 3 410