Sometimes, it is useful to give a single name to an entire list of
numbers, and treat the list as one entity. You do this by using **numerical
arrays.** A numerical array is the name of a block of storage locations,
just as a numerical variable is the name of a single storage location.

The simplest kind of array is the **linear array**. Think of a
linear array as a list of numbers arranged in a line. Each **element**,
or position in the line, has an **index number**. The first position
(element) has index 0, the second has index l, and so on. You can refer to
a number stored in the array by giving the array name and the location
index.

Suppose array A consists of the numbers

1.1, 1.2, 1.3, 1.4, 1.5

A(0) is l.l, the first element (index number 0); A(3) is 1.4, the fourth element (index number 3).

You can use numerical variables or other numerical expressions as
indexes for arrays. For instance, when the Sorcerer sees OX(Q), it first
looks at the number in storage location Q; then the Sorcerer discards
fractional elements (this process is called **truncation**; notice
that this is not the same as rounding); now the Sorcerer has an index
number that specifies which part of the array OX to look at.

**Truncation:** Changing a mixed number (one with both whole and
fractional elements) to an integer by dropping the fractional elements (or
discarding everything to the right of the decimal point).

Examples:

NUMBER NUMBER TRUNCATED

8.5 8

7.09 7

0.999 0

-3.98 -3

Array subscripts must be non-negative or you get an FC (ILLEGAL FUNCTION CALL) error message.

Example:

100 FOR Y=0 TO 10

110 PRINT OX(Y) 120 NEXT Y

This program prints the first 11 elements of the array OX, in order. It does not matter what variable you use to call up the array. Q or A1 or BZ would do just as well. This produces the same results:

100 FOR BZ=0 TO 10

110 PRINT OX(BZ)

120 NEXT BZ

You must fill an array for it to be of much use.You do this in several ways.

Example:

You type:

10 FOR A=0 TO 5

20 READ B(A)

30 NEXT A

40 DATA 9,7.6,13.11,1.4,1,0.009

RUN

Sorcerer makes these assignments:

A(0)=9, A(1)=7.6, A(2)=13.11,
A(3)=1.4, A(4)=1, A(5)=.009

Now add:

50 FOR A=0 TO 5

60 PRINT B(A);

70 NEXT A

RUN

Sorcerer replies:

9 7.6 13.11 1.4 1.0 .009

By the way, to **access** (that's a fancy computer term that means "call
up") the elements of the array B, you need not necessarily use the
same variable that you used to fill the array. The following would produce
the same results:

50 FOR Z=0 TO 5

60 PRINT B(Z); 70 NEXT Z

You can perform the READ and the PRINT within the same loop.

Example:

You type:

10 FOR X1=0 TO 10

20 READ DV(X1)

30 PRINT DV(X1);

40 NEXT X1

50 DATA 10,9,8,7,6,5,4,3,2,1,0

RUN

Sorcerer replies: 10 9 8 7 6 5 4 3 2 1 0

You can also assign individual array elements with assignment statements.

Example:

You type:

10 C(0)=93:C(1)=107:C(2)=6

20 C(3)=13:C(4)=25:C(5)=88

40 C(6)=1:C(7)=11:C(8)=4:C(9)=37

50 C(10)=50

60 FOR MN=0 TO 10:PRINT C(MN);:NEXT

RUN

Sorcerer replies: 93 107 6 13 25 88 1 11 4 37

Another way to fill an array is with equal numerical steps.

Example:

You type:

10 FOR X=0 TO 10

20 LA(X)=X

30 PRINT LA(X);

40 NEXT X

RUN

Sorcerer replies: 0 1 2 3 4 5 6 7 8 9 10

The Sorcerer has filled the 11 elements of the array LA with the integers from 0 to 10.

Example:

You type:

10 FOR PQ=10 TO 0 STEP -2

20 ED(PQ)=PQ

30 NEXT PQ

40 FOR RS=9 TO 1 STEP -2

50 ED(RS)=RS

60 NEXT RS

70 FOR PQ=10 TO 0 STEP -1

80 PRINT ED(PQ);

90 NEXT PQ

RUN

Sorcerer replies: 10 9 8 7 6 5 4 3 2 1 0

The most general format for an array element is:

< Array name> (< numerical expression >)

Numerical array names obey the same rules as the names of numerical variables: the first character must be a letter, the name cannot contain any reserved words and the name cannot be longer than the length of a line (and, as we have seen before, should be no longer than two characters).

How does the Sorcerer tell the difference between a variable and an array, if their names are chosen in the same way? Arrays have parentheses, variables don't.

Examples:

variable name array name

A A(1)

A1 A1(1)

XY X(Y)

MN MN(OP)

OX0 OX(0)

Notice that A is a completely different variable from any element of the array A. (Be aware that using the same name for a variable and an array may confuse those trying to follow your program.)

If an array is to have elements with index numbers higher than 10 you
must tell the Sorcerer so with a **dimension statement**. The format
is:

DIM <array name> (< highest index number >)

Example:

10 DIM MI(17)

This tells the Sorcerer that MI is a linear array with 18 elements, indexes 0 through 17.

You can have as many elements in an array as you want, provided there is enough memory available to store them all. If you try to dimension an array too large, you get an OM error message (OUT OF MEMORY).

For clarity in programming (and to save memory space), you can dimension arrays with less than 11 elements. Some versions of BASIC require that all arrays be dimensioned. Some versions of BASIC do not use the 0 index.

You can also use a variable or other numerical expression to dimension an array, so that the size of the array depends on the value of the expression.

Example:

10 DIM EM(2*YR+6)

The Sorcerer truncates the value of the expression. If the expression is less than0 (that is, if you try to use a negative index), you get an FC error message (ILLEGAL FUNCTION CALL).

You can also dimension two or more arrays with the same DIM statement.

Example:

25 DIM A(17), B(X), SU(Y+3)

If the Sorcerer sees an array before it sees a DIM statement for that array, it assumes the array has 11 elements (that is, the index runs from 0 to 10). So the Sorcerer always knows how large an array is supposed to be: either you tell it (with a DIM statement) or else it assumes 11 elements.

*It is good programming practice to initialize all variables. Give
them the value you want them to start with before using them. For this
reason, before you use any array, you should dimension it with a DIM
statement and assign values to all elements you will use.*

You must be careful about calling for array elements. Remember that MI(K) is the element of MI whose index is K (whatever K might happen to be), just as MI(3) is the element with the index 3. If you ask for an element that doesn't exist, you will have problems.

Example:

10 DIM MI(5)

20 FOR X=0 TO 10

30 LET MI(X)=X

40 NEXT X

When you run this program, the Sorcerer assigns values to the elements of MI until it gets to X=6, then it becomes unhappy with your program. You are asking it to do something to M1(6), but in line 10 you said that there weren't any MIs past MI(5). The result is the error message BS ERROR IN 30 (Subscript out of range).

Consider almanacs, insurance tables, real estate tables, loan tables. These books are filled with tables that we can think of as arrays of elements with two sets of indexes. One index tells which row of the table an element is in, and the other index tells which column. The position of any one element can be referenced by giving two numbers, that of the row and that of the column. Draw a line across the row and another down the column; where the lines meet is the position of the elernent.

You've seen mileage tables on rnaps. A list of cities is printed across the top of the table, and a list down the side.

ANYTOWN YOURTOWN EVERYTOWN MILPITAS

ANYTOWN 0 1 2 3

YOURTOWN 1 0 1 2

EVERYTOWN 2 1 0 1

MILPITAS 3 2 1 0

To find the distance between two towns, look across the top for the first town and down the side for the second. At the intersection you find the distance between them. Imagine that a roadmap company has just bought a brand new Sorcerer, and they want to store all their information in numerical form in an array. To refer to each town they use this code:

ANYTOWN=0

YOURTOWN=1

EVERYTOWN=2

MILPITAS=3

Now the ANYTOWN** row **they call row #0, the YOURTOWN row they call
row #1, the EVERYTOWN row they call row #2 and the MILPITAS row they call
row #3. The ANYTOWN **column** is column #0, YOURTOWN, #1, EVERYTOWN,
#2 and MILPITAS, #3.

Since all information must now be digitalized, the table can no longer
be called "Mileages Between Various Cities." The roadmap people
call it instead "Array A." When they print the mileage table,
they put the code (on a map it's called the **legend**) neatly in a
corner, and print this table:

COLUMN COLUMN COLUMN COLUMN

#0 #1 #2 #3

ROW #0 0 1 2 3

ROW #1 1 0 1 2

ROW #2 2 1 0 1

ROW #3 3 2 1 0

If we define the first index to be the number of the row and the second
index to be the number of the column, then the element with index numbers
0 and 0 (written A(0,0)) is 0. The element with first index 0 and second
index 1 (written A(0,1)) is 1, and so forth. The index** positions **(instead
of the numbers occupying those positions) are shown in this table:

Array A

COLUMN COLUMN COLUMN COLUMN

#0 #1 #2 #3

ROW #0 A(0,0) A(0,1) A(0,2) A(0,3)

ROW #1 A(1,0) A(1,1) A(1,2) A(1,3)

ROW #2 A(2,0) A(2,1) A(2,2) A(2,3)

ROW #3 A(3,0) A(3,1) A(3,2) A(3,3)

We call this kind of array a **two-dimensional array**, because it
has two indexes, and can be seen to literally exist in two dimensions. If
the roadmap company publishes a book of its maps, it can refer to
individual elements by an array with three sets of indexes, one to tell
which row an element is in, one to tell which column and one to tell which
page. We call this a **three-dimensional array. **Imagine a game of
three-dimensional tic-tac-toe. Three levels, each three by three. You
could refer to any position on the board by a set of three indexes.
Looking straight down onto the game, you could call the back left position
of the top level TC(0,0,0), the element one to the right you could call
TC(0,1,0), you could call the position straight forward from the back left
TC(1,0,0), and the position immediately below TC(0,0,0) you could call
TC(0,0,1 ) (You won't have difficulty with this sort of notation if you
remember that we call the first element 0, the second, 1, the third, 2,
the nth position we call n-l.)

It's harder to visualize, but you can have an array with as many different indexes as you wish. The number of different indexes is just the dimension of the array.

Theoretically, in Standard BASIC you could have as many as 255 different index sets for an array, with each index running up to whatever you please. But remember that all the elements of an array have to fit somewhere into the Sorcerer's memory. If you have too many dimensions, or if the indexes run too high, you run out of storage locations and get an OM error message (OUT OF MEMORY).

How many elements an array can be assigned depends on the memory size of your Sorcerer. The amount of space required for an array is

(# of elements)*2+6+(# of djmensions)*2 bytes.

For example, a 48K Sorcerer allows a maximum two-dimensional array of 108 by 109 elements (as, A(107, 108)); a 32K Sorcerer allows up to 89 by 89 (as, A(89,89)) A 48K Sorcerer permits an array of up to 13 indexes, so long as the indexes are only 1 and 0, and a 32K Sorcerer up to 12. (That is, you could assign a value to A(1,1,1,1,1,1,1,1,1,1,1,1).) Sorcerers with smaller memories permit correspondingly smaller arrays. The 48K Sorcerer accepts a three-dimensional array with indexes of up to 22, 21 ,21 ; the 32K, up to 19, 19, 18.

You fill a multi-dimensional array the same way as a linear array. Let's say you wanted to store the results of multiplying together in all possible combinations three sets of eleven numbers:

10 FOR A=0 TO 10

20 FOR B=0 TO 10

30 FOR C=0 TO 10

40 LET X(A,B,C)=A*B*C

50 NEXT C,B,A

60 INPUT "PICK THREE INTEGERS FROM 0 TO 10";A,B,C

70 PRINT "THE PRODUCT OF YOUR THREE NUMBERS IS";X(A,B,C)

80 PRINT

90 GO TO 60

Notice that the program performs the multiplications once, in the process of filling the array. Thereafter it finds the product requested, not by multiplication, but by locating its position in the array. Also notice that once the array has been filled, the variables can be reused for other purposes. (Reusing variables saves memory space and speeds up programs.)

Here is a program that uses a one dimensional array to sort a group of numbers. This sort program is sometimes called a "bubble sort," because each pass through the loop the smallest number "floats" to the top. Notice the use of a temporary "holding variable" (TV) each time two numbers are switched. Line 90 asks the question, is A(K) larger? If so, "float" it to the top: if not, switch.

10 REM A SORT PROGRAM

20 INPUT "HOW MANY NUMBERS DO YOU WISH TO SORT";X

30 DIM A(X)

40 FOR Y=1 TO X

50 PRINT "ENTER #"Y;:INPUT A(Y)

60 NEXT Y

70 FOR J=1 TO X-1

80 FOR K=J+1 TO X

90 IF A(K)>A(J) THEN 130

100 TV=A(J)

110 A(J)=A(K)

120 A(K)=TV

130 NEXT K

140 NEXT J

150 PRINT

160 PRINT "HERE ARE YOUR NUMBERS SORTED:"

170 FOR Y=1 TO X

180 PRINT A(Y)

190 NEXT Y

Volumes have been written on sort programs. The preceding is by no means the fastest or most efficient. For faster execution, substitute this for lines 70 to 120.

70 FOR J=2 T0 X

80 FOR K=J TO 2 STEP -1

90 IF A(K)>A(K-1) THEN 140

100 TV=A(K)

110 A(K)=A(K-1)

120 A(K-1)=TV

The next sort program runs relatively slowly, but is easy to follow. It keeps looking through the entire list of numbers. If the number it encounters is larger than the next number, it switches them, and then goes to the next one. It sets a flag (FL) to zero each pass, and to 1 for each switch. If no switch is made, the flag remains zero. When the program can look at each number and make no switches then all the numbers are sorted. At that point, it prints the array.

10 INPUT "HOW MANY NUMBERS DO YOU WISH TO SORT";X

20 DIM A(X)

30 FOR Y=1 TO X

40 PRINT "ENTER #"Y;:INPUT A(Y)

50 NEXT Y

60 FL=0

70 FOR I=1 TO X-1

80 IF A(I)<=A(I+1) THEN 110

90 TV=A(I):A(I)=A(I+1):A(I+1)=TV

100 FL=1

110 NEXT I

120 IF FL=1 THEN 60

130 PRINT "HERE ARE YOUR NUMBERS SORTED:"

140 FOR Y=1 TO X

150 PRINT A(Y)

160 NEXT Y

RUN

HOW MANY NUMBERS DO YOU WISH TO SORT? 5

ENTER # 1 ? 376

ENTER # 2 ? 0

ENTER # 3 ? .03

ENTER # 4 ? -5

ENTER # 5 ? 13.65

HERE ARE YOUR NUMBERS SORTED:

-5

0

.03

13.65

376