Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.


9.2.5 Extracting data (dereferencing pointers)

If you have an address stored in a variable (i.e., a pointer) you can extract the data using the ^ operator. This is called dereferencing the pointer. The ^ operator should only really be used when {var} has been used to obtain an address. To this end, LONG values are read and written when dereferencing pointers in this way. For pointers to non-simple types (e.g., objects and arrays), dereferencing is achieved in much more readable ways (see the appropriate section for details), and this operator is not used. In fact, ^var is seldom used in programs, but is useful for explaining how pointers work, especially in conjunction with {var}.

Using pointers can remove the scope restriction on local variables, i.e., they can be altered from outside the procedure for which they are local. Whilst this kind of use is not generally advised, it makes for a good example which shows the power of pointers. For example, the following program changes the value of the local variable x for the procedure fred from within the procedure barney. It can do this only because fred passes a pointer to x as a parameter to barney.

PROC main()
  fred()
ENDPROC

PROC fred()
  DEF x, p:PTR TO LONG
  x:=33
  p:={x}
  barney(p)
  WriteF('x is now \d\n', x)
ENDPROC

PROC barney(ptr:PTR TO LONG)
  DEF val
  val:=^ptr
  ^ptr:=val-6
ENDPROC

Here's what you can expect it to generate as output:

x is now 27

Notice that the ^ operator (i.e., dereferencing) is quite versatile. In the first assignment of the procedure barney it is used (with the pointer ptr) to get the value stored in the local variable x, and in the second it is used to change this variable's value. In either case, dereferencing makes the pointer behave exactly as if you'd written the variable to which it points. To emphasise this, we can remove the barney procedure, like we did above (see 2.5 Style, Reuse and Readability):

PROC main()
  fred()
ENDPROC

PROC fred()
  DEF x, p:PTR TO LONG, val
  x:=33
  p:={x}
  val:=x
  x:=val-6
  WriteF('x is now \d\n', x)
ENDPROC

Everywhere the barney procedure used ^ptr we've written x (because we are now in the procedure for which x is local). We've also eliminated the ptr variable (the parameter to the barney procedure), since it was only used with the ^ operator.

To make things clear the fred and barney example is deliberately `wordy'. The val and p variables are unnecessary, and the pointer types could be abbreviated to LONG or even omitted, for the reasons outlined above (see 9.1 LONG Type). This is the compact form of the example:

PROC main()
  fred()
ENDPROC

PROC fred()
  DEF x
  x:=33
  barney({x})
  WriteF('x is now \d\n', x)
ENDPROC

PROC barney(ptr)
  ^ptr:=^ptr-6
ENDPROC

By far the most common use of pointers is to address (or reference) large structures of data. It would be extremely expensive (in terms of CPU time) to pass large amounts of data from procedure to procedure, so addresses to such data are passed instead (and, as we know, these are just 32-bit values). The Amiga system functions (such as ones for creating windows) require a lot of structured data, so if you plan to do any real programming you are going to have to understand and use pointers.

As we have seen, if you have a pointer to some data you can easily read the data, but you can just as easily alter it. If you want to write code that is clear and understandable, you have an implicit responsibility to not use pointers to alter data that you didn't ought to. For instance, if a procedure is passed a pointer which it then uses to change the data being pointed to, then it ought to be well documented (using comments) exactly what changes it makes.


Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.