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


14.3 Dynamic Allocation

Dynamically allocated memory is any memory that is not statically allocated. To allocate memory dynamically you can use the List and String functions, all flavours of New, and the versatile NEW operator. But because the memory is dynamically allocated it must be explicitly deallocated when no longer needed. In all the above cases, though, any memory that is still allocated when the program terminates will be deallocated automatically.

Another way to allocate memory dynamically is to use the Amiga system functions based on AllocMem. However, these functions require that the memory allocated using them be deallocated (using functions like FreeMem) before the program terminates, or else it will never be deallocated (not until your machine is rebooted, anyway). It is safer, therefore, to try to use the E functions for dynamic allocation whenever possible.

There are many reasons why you might want to use dynamic allocation, and most of them involve initialisation of pointers. For example, the declarations in the section about static allocation can be extended to give initialisations for the pointers declared in the second DEF line (see 14.1 Static Allocation).

  DEF a[20]:ARRAY,   m:myobj,        s[10]:STRING

  DEF a:PTR TO CHAR, m:PTR TO myobj, s:PTR TO CHAR
  a:=New(20)
  m:=New(SIZEOF myobj)
  s:=String(20)

These are initialisations to dynamically allocated memory, whereas the first line of declarations initialise similar pointers to statically allocated memory. If these sections of code were part of a procedure then, since they would now be local variables, there would be one other, significant difference: the dynamically allocated memory would not automatically be deallocated when the procedure returns, whereas the statically allocated memory would. This means that we can solve the deallocation problem (see 14.2 Deallocation of Memory).

/* This is the correct way of doing it */
PROC fullname(first, last)
  DEF full
  full:=String(40)
  StrCopy(full, first)
  StrAdd(full, ' ')
  StrAdd(full, last)
ENDPROC full

PROC main()
  DEF f, g
  WriteF('Name is \s\n', fullname('Fred', 'Flintstone'))
  f:=fullname('Fred', 'Flintstone')
  g:=fullname('Barney', 'Rubble')
  WriteF('Name is \s\n', f)
ENDPROC

The memory for the E-string pointed to by full is now allocated dynamically, using String, and is not deallocated until the end of the program. This means that it is quite valid to pass the value of full as the result of the procedure fullname, and it is quite valid to dereference the result by printing it using WriteF. However, this has caused one last problem: the memory is not deallocated until the end of the program, so is potentially wasted since it could be used, for example, to hold the results of subsequent calls. Of course, the memory can be deallocated only when the data it stores is no longer required. The following replacement main procedure shows when you might want to deallocate the E-string (using DisposeLink).

PROC main()
  DEF f, g
  f:=fullname('Fred', 'Flintstone')
  WriteF('Name is \s, f points to $\h\n', f, f)
/* Try this with and without the next DisposeLink line */
  DisposeLink(f)
  g:=fullname('Barney', 'Rubble')
  WriteF('Name is \s, g points to $\h\n', g, g)
  DisposeLink(g)
ENDPROC

If you run this with the DisposeLink(f) line you'll probably find that g will be a pointer to the same memory as f. This is because the call to DisposeLink has deallocated the memory pointed to by f, so it can be reused to store the E-string pointed to by g. If you comment out (or delete) the DisposeLink line, then you will find that f and g always point to different memory.

In some ways it is best to never do any deallocation, because of the problems you can get into if you deallocate memory too early (i.e., before you've finished with the data it contains). Of course, it is safe (but temporarily wasteful) to do this with the E dynamic allocation functions, but it is very wasteful (and wrong) to do this with the Amiga system functions like AllocMem.

Another benefit of using dynamic allocation is that the size of the arrays, E-lists and E-strings that can be created can be the result of any expression, so is not restricted to constant values. (Remember that the size given on ARRAY, LIST and STRING declarations must be a constant.) This means that the fullname procedure can be made more efficient and allocate only the amount of memory it needs for the E-string it creates.

PROC fullname(first, last)
  DEF full
  /* The extra +1 is for the added space */
  full:=String(StrLen(first)+StrLen(last)+1)
  StrCopy(full, first)
  StrAdd(full, ' ')
  StrAdd(full, last)
ENDPROC full

However, it may be very complicated or inefficient to calculate the correct size. In these cases, a quick, constant estimate might be better, overall.

The various functions for allocating memory dynamically have corresponding functions for deallocating that memory. The following table shows some of the more common pairings.

Allocation       Deallocation
------------------------------
New              Dispose
NewR             Dispose
List             DisposeLink
String           DisposeLink
NEW              END
FastNew          FastDispose
AllocMem         FreeMem
AllocVec         FreeVec
AllocDosObject   FreeDosObject

NEW and END are versatile and powerful operators, discussed in the following section. The functions beginning with Alloc- are Amiga system functions and are paired with similarly suffixed functions with a Free- prefix. See the Rom Kernel Reference Manual for more details.


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