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


9.5.7 Static data

String constants (e.g., `fred'), lists (e.g., [1,2,3]) and typed lists (e.g., [1,2,3]:INT) are static data. This means that the address of the (initialised) data is fixed when the program is run. Normally you don't need to worry about this, but, for instance, if you want to have a series of lists as initialised arrays you might be tempted to use some kind of loop:

PROC main()
  DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  FOR i:=0 TO 9
    a[i]:=[1, i, i*i]
      /* This assignment is probably not what you want! */
  ENDFOR
  FOR i:=0 TO 9
    p:=a[i]
    WriteF('a[\d] is an array at address \d\n', i, p)
    WriteF('  and the second element is \d\n', p[1])
  ENDFOR
ENDPROC

The array a is an array of pointers to initialised arrays (which are all three elements long). But, as the comment suggests and the program shows, this probably doesn't do what was intended, since the list is static. That means the address of the list is fixed, so each element of a gets the same address (i.e., the same array). Since i is used in the list, the contents of that part of memory varies slightly as the first FOR loop is processed. But after this loop the contents remain fixed, and the second element of each of the ten arrays is always nine. This is an example of the output that will be generated (the `...' represents a number of similar lines):

a[0] is an array at address 4021144
  and the second element is 9
a[1] is an array at address 4021144
  and the second element is 9
...
a[9] is an array at address 4021144
  and the second element is 9

One solution is to use the dynamic typed-allocation operator NEW (see 14.4 NEW and END Operators). Another solution is to use the function List and copy the normal list into the new E-list using ListCopy:

PROC main()
  DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
  FOR i:=0 TO 9
    a[i]:=List(3)
    /* Must check that the allocation succeeded before copying */
    IF a[i]<>NIL THEN ListCopy(a[i], [1, i, i*i], ALL)
  ENDFOR
  FOR i:=0 TO 9
    p:=a[i]
    IF p=NIL
      WriteF('Could not allocate memory for a[\d]\n', i)
    ELSE
      WriteF('a[\d] is an array at address \d\n', i, p)
      WriteF('  and the second element is \d\n', p[1])
    ENDIF
  ENDFOR
ENDPROC

The problem is not so bad with string constants, since the contents are fixed. However, if you alter the contents explicitly, you will need to take care not to run into the same problem, as this next example shows.

PROC main()
  DEF i, strings[10]:ARRAY OF LONG, s:PTR TO CHAR
  FOR i:=0 TO 9
    strings[i]:='Hello World\n'
      /* This assignment is probably not what you want! */
  ENDFOR
  s:=strings[4]
  s[5]:="X"
  FOR i:=0 TO 9
    WriteF('strings[\d] is ', i)
    WriteF(strings[i])
  ENDFOR
ENDPROC

This is an example of the output that will be generated (again, the `...' represents a number of similar lines)::

strings[0] is HelloXWorld
strings[1] is HelloXWorld
...
strings[9] is HelloXWorld

The solution, once more, is to use dynamic allocation. The functions String and StrCopy should be used in the same way that List and ListCopy were used above.


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