20. Ukazovatele: POINTER, ^, @
Na čo to je
Každá premenná leží niekde v pamäti – na svojej adrese. Adresa je číslo od 0 do 65535, ako číslo domu na dlhej ulici. Ukazovateľ je premenná, v ktorej je adresa inej premennej. Cez ukazovateľ sa dá k tej premennej dostať, aj keď nepoznáš jej meno.
Hodí sa to v dvoch prípadoch: keď má rutina zmeniť premennú volajúceho, a keď sa prechádza pamäťou bajt po bajte.
Ako sa to píše
BYTE POINTER p ; ukazovateľ na BYTE
CARD POINTER q ; ukazovateľ na CARD
| Zápis | Číta sa | Význam |
|---|---|---|
@x | „adresa x“ | adresa premennej x |
p=@x | do p ulož adresu x – p teraz ukazuje na x | |
p^ | „to, na čo ukazuje p“ | hodnota na adrese uloženej v p |
p^=5 | ulož 5 tam, kam p ukazuje |
Typ pred slovom POINTER hovorí, čo na danej adrese leží: BYTE POINTER číta a zapisuje jeden bajt, CARD POINTER dva.
Celý program
Súbor examples/pointers.act:
; Pointers: variables that hold an address
PROC Swap(BYTE POINTER a, b)
BYTE keep
keep=a^
a^=b^
b^=keep
RETURN
PROC Main()
BYTE x, y, i
BYTE POINTER p
BYTE ARRAY data=[5 8 13 21]
x=10
y=20
p=@x ; p holds the address of x
Print("p points at x: ") PrintBE(p^)
p^=15 ; store through the pointer
Print("x is now ") PrintBE(x)
p=@y ; the same pointer, another variable
Print("p points at y: ") PrintBE(p^)
Swap(@x, @y) ; the routine changes our variables
Print("After Swap: x=") PrintB(x)
Print(" y=") PrintBE(y)
p=data ; the name of an array is its address
Print("The array: ")
FOR i=1 TO 4
DO
PrintB(p^) Put(' )
p==+1 ; move to the next byte
OD
PutE()
RETURNPreklad a spustenie
action26 pointers.act --simČo uvidíš
p points at x: 10
x is now 15
p points at y: 20
After Swap: x=20 y=15
The array: 5 8 13 21 Ako to funguje
p=@x– vpje adresa premennejx.p^je potom to isté akox.p^=15zapíše 15 na tú adresu. Keď potom vypíšešx, je v ňom 15, hoci si doxpriamo nič nepriradil.p=@y– ten istý ukazovateľ môže postupne ukazovať na rôzne premenné.
Rutina, ktorá mení premenné volajúceho
Z kapitoly 14 vieš, že procedúra dostáva kópie. Swap má premenné vymeniť, takže kópie jej nestačia. Dostane preto ich adresy (Swap(@x, @y)) a cez a^ a b^ pracuje priamo s premennými x a y v Main.
Takto môže rutina „vrátiť“ viac hodnôt naraz.
Ukazovateľ a pole
Meno poľa bez indexu je adresa jeho prvého prvku. Preto p=data (bez @) nastaví p na začiatok poľa. p==+1 potom posunie ukazovateľ o jeden bajt a slučka prejde pole bez indexov.
Platí to aj naopak: ukazovateľ sa dá indexovať ako pole, p(2) je bajt dva miesta za adresou v p.
Pole deklarované bez veľkosti a bez hodnôt (BYTE ARRAY a) je vlastne ukazovateľ: nemá vlastné prvky a treba mu najprv priradiť adresu.
Časté chyby
| Čo sa stalo | Čo sa stane |
|---|---|
p=x namiesto p=@x | do p sa uloží hodnota x ako adresa; p^ potom číta náhodné miesto v pamäti |
| použitie ukazovateľa, do ktorého si nič nepriradil | čítanie alebo zápis na náhodnú adresu; zápis môže zhodiť program aj počítač |
p==+1 pri CARD POINTER | posunie adresu o 1 bajt, nie o jeden CARD – na ďalší CARD treba p==+2 |
| typ ukazovateľa nesedí s tým, na čo ukazuje | CARD POINTER na BYTE premennú zapíše dva bajty a prepíše aj susednú premennú |
Prekladač tieto chyby nehlási. Ukazovateľ je silný nástroj práve preto, že ti dovolí siahnuť kamkoľvek do pamäte – aj tam, kam nemáš.
Pri treťom riadku si pomôžeš indexom: q(1) pri CARD POINTER q je druhý CARD, index sa veľkosťou prvku násobí sám.
Vyskúšaj si
- Napíš procedúru
Reset(BYTE POINTER p), ktorá vynuluje premennú, na ktorú dostane adresu. - Napíš procedúru
MinMax(BYTE a, b, BYTE POINTER min, max), ktorá uloží menšie z dvoch čísel domin^a väčšie domax^. - Prejdi pole
dataukazovateľom a spočítaj súčet jeho prvkov.
Zhrnutie
- Ukazovateľ je premenná s adresou inej premennej.
@xje adresax;p^je hodnota na adrese vp.- Rutina, ktorá dostane adresu, môže zmeniť premennú volajúceho.
- Meno poľa je adresa jeho začiatku.
- Ukazovateľ treba najprv nastaviť; chyby s ukazovateľmi prekladač nezachytí.
Späť: 19. Reťazce · Ďalej: 21. Záznamy