logo

C Kaksoisosoitin (osoittimesta osoittimeen)

Kuten tiedämme, osoitinta käytetään C:n muuttujan osoitteen tallentamiseen. Osoitin lyhentää muuttujan hakuaikaa. C:ssä voimme kuitenkin myös määrittää osoittimen tallentamaan toisen osoittimen osoitteen. Tällainen osoitin tunnetaan kaksoisosoittimena (pointer to pointer). Ensimmäistä osoitinta käytetään tallentamaan muuttujan osoite, kun taas toista osoitinta käytetään tallentamaan ensimmäisen osoittimen osoite. Ymmärretään se alla olevan kaavion avulla.

osoitin osoittimeen kohdassa c

Kaksoisosoittimen ilmoittamisen syntaksi on annettu alla.

 int **p; // pointer to a pointer which is pointing to an integer. 

Harkitse seuraavaa esimerkkiä.

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

Lähtö

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

C-kaksoisosoitin esimerkki

Katsotaanpa esimerkkiä, jossa yksi osoitin osoittaa toisen osoittimen osoitteeseen.

C osoittimesta osoittimeen esimerkki

Kuten yllä olevasta kuvasta näkyy, p2 sisältää p:n osoitteen (fff2) ja p sisältää numeromuuttujan osoitteen (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; } 

Lähtö

 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 

K. Mikä on seuraavan ohjelman tulos?

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

Selitys

Kaksoisosoittimen kysymys

Yllä olevassa kysymyksessä osoittimen aritmetiikkaa käytetään kaksoisosoittimen kanssa. Määritetään 6 elementin taulukko, jota osoittaa osoittimen p matriisi. Osoitintaulukkoa p osoittaa kaksoisosoitin pp. Yllä oleva kuva antaa kuitenkin lyhyen käsityksen siitä, kuinka muistia varataan taulukolle a ja osoitintaulukolle p. P:n elementit ovat osoittimia, jotka osoittavat jokaiseen taulukon a elementtiin. Koska tiedämme, että taulukon nimi sisältää taulukon kantaosoitteen, se toimii osoittimena ja voidaanko arvo kulkea käyttämällä *(a), *(a+1) jne. Kuten kuvassa , a[0] voidaan käyttää seuraavilla tavoilla.

  • a[0]: se on yksinkertaisin tapa päästä käsiksi taulukon ensimmäiseen elementtiin
  • *(a): Koska taulukko tallentaa taulukon ensimmäisen elementin osoitteen, voimme käyttää sen arvoa käyttämällä siinä epäsuoraa osoitinta.
  • *p[0]: jos a[0]:aan päästään käyttämällä siihen osoittavaa osoitinta p, niin voimme käyttää indirection-operaattoria (*) osoitintaulukon p ensimmäisessä elementissä, eli *p[0].
  • **(pp): koska pp tallentaa osoitintaulukon perusosoitteen, *pp antaa osoitintaulukon ensimmäisen elementin arvon, joka on kokonaislukutaulukon ensimmäisen elementin osoite. **p antaa kokonaislukutaulukon ensimmäisen alkion todellisen arvon.

Ohjelmaan tullessa rivit 1 ja 2 ilmoittavat kokonaisluvun ja osoitintaulukon suhteellisesti. Rivi 3 alustaa kaksoisosoittimen osoitintaulukkoon p. Kuten kuvasta näkyy, jos taulukon osoite alkaa arvosta 200 ja kokonaisluvun koko on 2, osoitintaulukko sisältää arvot 200, 202, 204, 206, 208, 210. Otetaan, että osoitintaulukon perusosoite on 300; kaksoisosoitin pp sisältää osoitintaulukon osoitteen, eli 300. Rivi numero 4 lisää pp:n arvoa yhdellä, eli pp osoittaa nyt osoitteeseen 302.

Rivi numero 5 sisältää lausekkeen, joka tulostaa kolme arvoa, eli pp - p, *pp - a, **pp. Lasketaan ne jokainen niistä.

  • pp = 302, p = 300 => pp-p = (302-300)/2 => pp-p = 1, eli 1 tulostetaan.
  • pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1, eli 1 tulostetaan.
  • pp = 302, *pp = 202, *(*pp) = 206, eli 206 tulostetaan.

Siksi rivin 5 tuloksena tulosteet 1, 1, 206 tulostetaan konsoliin. Rivillä 6 kirjoitetaan *pp++. Tässä on huomioitava, että kahdella unaarioperaattorilla * ja ++ on sama etusija. Siksi assosiatiivisuussäännön mukaan sitä arvioidaan oikealta vasemmalle. Siksi lauseke *pp++ voidaan kirjoittaa uudelleen muotoon (*(pp++)). Koska pp = 302, josta tulee nyt 304. *pp antaa 204.

Rivillä 7 kirjoitetaan jälleen lauseke, joka tulostaa kolme arvoa, eli pp-p, *pp-a, *pp. Lasketaan jokainen niistä.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, eli 2 tulostetaan.
  • pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2, eli 2 tulostetaan.
  • pp = 304, *pp = 204, *(*pp) = 300, eli 300 tulostetaan.

Siksi rivin 7 tuloksena tulosteet 2, 2, 300 tulostetaan konsoliin. Rivillä 8 kirjoitetaan ++*pp. Assosiatiivisuussäännön mukaan tämä voidaan kirjoittaa uudelleen muotoon, (++(*(pp))). Koska pp = 304, *pp = 204, arvo *pp = *(p[2]) = 206, joka nyt osoittaa a[3].

Rivillä 9 kirjoitetaan jälleen lauseke, joka tulostaa kolme arvoa, eli pp-p, *pp-a, *pp. Lasketaan jokainen niistä.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, eli 2 tulostetaan.
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, eli 3 tulostetaan.
  • pp = 304, *pp = 206, *(*pp) = 409, eli 409 tulostetaan.

Siksi rivin 9 tuloksena tuloste 2, 3, 409 tulostetaan konsoliin. Rivillä 10 kirjoitetaan ++**pp. assosiatiivisuuden säännön mukaan tämä voidaan kirjoittaa uudelleen muotoon, (++(*(*(pp)))). pp = 304, *pp = 206, **pp = 409, ++**pp => *pp = *pp + 1 = 410. Toisin sanoen a[3] = 410.

Rivillä 11 kirjoitetaan jälleen lauseke, joka tulostaa kolme arvoa, eli pp-p, *pp-a, *pp. Lasketaan jokainen niistä.

  • pp = 304, p = 300 => pp - p = (304 - 300)/2 => pp-p = 2, eli 2 tulostetaan.
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3, eli 3 tulostetaan.
  • Rivillä 8 **ss = 410.

Siksi rivin 9 tuloksena tulos 2, 3, 410 tulostetaan konsoliin.

Lopuksi koko ohjelman tulos annetaan seuraavasti:

Lähtö

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