• Keine Ergebnisse gefunden

The Exit Procedure

Im Dokument Turbo Pascal® Tutor (Seite 174-181)

Sometimes in writing a procedure or function, you reach a point in the middle of the body of the procedure at which it would be handy to return immediately-without executing the rest of the procedure-to the calling program. Standard Pascal offers no way to do this; you must structure the procedure (using if statements, perhaps) so that all statements from then on to the end of the procedure can be skipped.

Here's a sample program that shows how involved things can get in Standard Pascal. Function RunningTotal accepts numbers from the keyboard, one at a time, then returns the total:

function RunningTotal Real;

Such a value, used as a signal to the program to do something, is known as a sentinel. Here, the sentinel value -1 indicates that there are no more numbers to be entered. While RunningTotal works, it is both confusing and inefficient. In particular, we test twice to see if variable NewNumber has the value -1: once to determine whether to add it to the running total and a second time to see if we should leave the procedure.

The second test wouldn't be necessary if we could put a statement in the repeat. .. until loop that says, "If NewNumber is -1, return the total immediately without doing anything else." Turbo Pascal allows a return from any point in a procedure or function with the predefined procedure Exit. Using Exit both simplifies and speeds up RunningTotal:

function RunningTotal Real;

This technique becomes even more important when the point from which you want to exit is deeply nested in structured statements, such as its and whiles. It can also make your program more readable, since the reader will be able to recognize immediately where the exit occurs and what value is returned.

As you might guess, calling Exit from within the main program causes the program to terminate-it's like hitting the final end.

Review

In this chapter, we introduced the two types of program subdividers in Pascal: procedures and functions. We described the format of procedure and function declarations, and we explained Pascal's rules about the scope and lifetime of identifiers declared within procedures and functions.

We touched on the topic of recursion. We discussed how to declare forward procedures and functions and how to determine the scope of identifiers during recursion. Finally, we presented the predefined procedure Exit, which causes an immediate exit from a subprogram or main program.

In the next chapter, we cover arrays: what they are and how to use them.

c

H A p T E R

12

Arrays

We've discussed the five predefined data types-Integer, LengInt, Real, Boolean, and Char-as well as declared scalar types. A variable of one of these types can hold only one value at a time. For example, if you define var

Index : Integer;

Index has a single value at any moment. There are situations in which it's convenient for a single identifier to represent a series of values, such as a list of numbers or characters. That's where arrays come in.

Suppose, for example, you want to write a program to balance your checkbook. One thing your program will need is a list of all your checks and the amounts they were written for. To reserve space for this information, you could declare a variable for each check:

var

Checkl : Real; { Amount of check 1 } Check2 : Real; { Amount of check 2 } Check3 : Real; { Amount of check 3 }

Check50 : Real; { Amount of check 50 }

This approach quickly becomes tedious if you write a lot of checks. Also, it is impossible to write a loop to go through all the checks and do something with each-say, add them to a running total. You can't write the following:

for Check := Checkl to Check50 do Total := Total + Check;

Arrays 155

How, then, do we accomplish the task we've described? The answer is to store the check amounts in an array.

An array is a list of variables of identical type, each of which can be referred to. by specifying the name of the list and the variable's position in the list.

Suppose that you declare var

Check: array[1 .. 10] of Real;

This declaration tells the compiler that identifier Check refers to a list of ten variables of type Real, each with a number (called its index) from 1 to 10.

Each item of an array is referred to by the name of the array, followed by its index enclosed in square brackets ([D. Thus, array Check contains the 10 variables Check[ll, Check[2], Check[3], Check[4], Check[S], Check[6], Check[7], Check[8), Check[9}, and Check[10}. You can use any of these variables wherever you would use a regular Real variable. Furthermore-and this is what makes arrays useful-the index value doesn't have to be a constant. It can be any expression that yields an integer in the range 1..10. For example, if the variable Index is of the type Integer, the statement

for Index := 1 to 10 do Check [Index] := 0.0;

zeros each variable.

How do arrays solve the problem of adding up check amounts? You can now refer to each check by its index and write

Total := 0.0; { initialize the "accumulator" variable for Index := 1 to 10 do

Total := Total + Check[Index];

Figure 12.1 shows the syntax of an array type.

array type

--.c

array

~

index type

~

L...----tO\olll41----'

Figure 12.1: Syntax Diagram of an Array Type

To specify an array type, you must give the compiler two pieces of information: the array's index type and the type of each of the items of the array, the base type.

The index type, which appears between the square brackets, must be scalar, usually an integer subrange, for example, 1 . .10. Occasionally another type is appropriate. For example, for a program to encrypt a secret message using a cipher, you might want an array that holds the code for each possible object of the type Char. In that case, you could declare the array var

Cipher : array [char] of char;

filling each location of the array with the replacement character for the corresponding index character. Then, to encode a character, you could write MsgChar := Cipher[MsgChar];

and each character in the secret message would be replaced by the code for that character.

There are other limits to the index type of an array, one being that the type cannot have so many possible values that the total size of the array is greater than 32,767 bytes (32K). The declaration

type

BigArrayType = array[1 .. 20000] of Integer;

causes a Structure Too Large error during compilation, because a list of 20,000 integers, at 2 bytes each, requires 40,000 bytes.

The reason for this constraint stems from the Macintosh's processor. While the processor can work with objects larger than 32K, its most efficient (fastest) addressing mode is restricted. to objects less than 32K bytes long.

We'll come up against the 32K limitation again in other contexts as well.

There are various ways around the 32K array size limitation, allowing the creation of objects as large as you have memory for. We'll deal with this topic in detail in Chapters 16 and 23.

It can be handy to use an enumerated type in declaring an array:

type

Array Regular consists of five integers. If an Integer variable occupies 2 bytes and a Boolean 1 byte, can you tell the total amount of memory (in bytes)

Arrays 157

taken up by each array? (Note that the compiler always pads data structures out to an even length, for example, 5-byte data structures are padded to 6 bytes.) The answers are 10, 14, and 8.

The base type of an array can be almost any data type at all-just as long as the total size of the array does not exceed 32,767 bytes. In fact, you can declare arrays that contain other structured types, including other arrays-there's that recursive quality of Pascal again. Arrays of arrays (called multidimensional arrays) are useful for describing objects in a table or grid, such as a cell in a spreadsheet (which is located by its row and column) or a point on a piece of graph paper (located by its horizontal and vertical coordinates).

Consider a program that plays checkers. An important data structure for this program would be the array that tracks the state of the board. One way to represent the board might be like this:

type

Square = (RedSquare, EmptyBlackSquare, RedPiece, BlackPiece, RedKing, BlackKing); {possible contents of a square}

var

CheckerBoard: array [1 .. 8) {outer array} of

array [1 .. 8) {inner array} of Square;

How would you access a particular square of the board given this declaration of array CheckerBoard? In Pascal, you specify the subscript of the outer array, followed by the subscript of the inner array. Thus, if you let each of the inner arrays be a column (horizontal file) of the board, you could specify the square in the third column from one player's left and the fourth row (vertical rank) from the same side of the board (see Figure 12.2).

R

Im Dokument Turbo Pascal® Tutor (Seite 174-181)