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

Action!
BYTE POINTER p      ; ukazovateľ na BYTE
CARD POINTER q      ; ukazovateľ na CARD
ZápisČíta saVýznam
@x„adresa x“adresa premennej x
p=@xdo p ulož adresu x – p teraz ukazuje na x
p^„to, na čo ukazuje p“hodnota na adrese uloženej v p
p^=5ulož 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:

Action!
; 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()
RETURN

Preklad 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

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=@xdo 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 POINTERposunie adresu o 1 bajt, nie o jeden CARD – na ďalší CARD treba p==+2
typ ukazovateľa nesedí s tým, na čo ukazujeCARD 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

  1. Napíš procedúru Reset(BYTE POINTER p), ktorá vynuluje premennú, na ktorú dostane adresu.
  2. Napíš procedúru MinMax(BYTE a, b, BYTE POINTER min, max), ktorá uloží menšie z dvoch čísel do min^ a väčšie do max^.
  3. Prejdi pole data ukazovateľom a spočítaj súčet jeho prvkov.

Zhrnutie

Späť: 19. Reťazce · Ďalej: 21. Záznamy