Lesson 6

Arrays

 

Arrays, in computers, are collections of variables which are referenced by a single identifier. The separate memory cells are referenced by subscripts or, in simpler terms, cell number.

The contents of every cell must be of the same data type.

In order to use an array, you must first declare it, like any other data types you use. This is the declaration syntax:-

 

ARRAY [subrange-1 (,subrange-2, subrange-3)] OF base_type;

 

The declaration must be associated with a TYPE or a VARiable. The full declaration in order to make use of the array is like this:-

 

TYPE

Array_Type = ARRAY [ sub-1 (,sub-2,sub-3) ] OF base_type;

VAR

Array_Used : Array_Type;

 

 

* sub indicates subranges.

 

The SUBRANGEs used in the declaration must be of ordinal types.

BASE_TYPE of an array can be of any of the standard types or a user defined type. Each and every subrange specified indicates a DIMENSION.

 

Here is a sample program which demonstrates how to put values into the array and output them

 

program ManipulateArrays;

 

uses CRT;

 

type

NumArray = array [ 1..10 ] of integer;

 

var

Numbers : NumArray;

I : integer;

Sum : integer;

Average : real;

 

begin { main program }

 

ClrScr;

Sum := 0; Average := 0;

WriteLn('Type in 10 numbers. Hit <ENTER> after every number');

 

{ get 10 numbers and store into array }

for I := 1 to 10 do

begin

Write('Number (',I,') : ');

ReadLn( Numbers[ I ] );

end;

 

{ print out the 10 numbers and calculate the sum }

WriteLn;

WriteLn('Numbers in the array.');

for I := 1 to 10 do

begin

Write( Numbers[ I ]:5 );

Sum := Sum + Numbers[ I ];

end;

 

Average := Sum / 10;

 

WriteLn;

WriteLn('The sum of the numbers is ', Sum );

WriteLn('The average is ', Average:4:3);

ReadLn;

end. { main program }

 

This is how the array NUMBERS can be represented diagrammatically:

 

                   

[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

 

with each cell storing an integer.

 

Looking at this example, you will see the array declared under the TYPE heading and then later it is used in the VAR section. The TYPE heading allows you to define your own data types other than the ones already provided (eg. Char, Integer, Real, Boolean etc.). Any identifier declared under the TYPE heading is a user defined data type and not a variable. It does not reference or has association to any memory areas.

 

If the array is to exist in memory, it must have an identifier under the VARiable declaration section. The variable NUMBERS is the name which is used when the array is to be referenced, not NUMARRAY. Looking at NUMARRAY you will see that NUMBERS has been declared as an array of ten cells ( array [1..10] ) and it can only store integers ( OF integer; ). This means that NUMBERS has got, not one but, ten memory cells and these cells can store one integer each.

 

In the program, the identifier NUMBERS is followed by square brackets which has a variable in between. This variable used in the square brackets is known as the subscript of the array. The subscript variable used in the program must be of the same type as the subrange declared for the array at the beginning of the program.

 

Whenever arrays are used, the most important thing to be considered is the array's subscript or cell number. The value of the subscript indicates where the value is stored in a certain array. Another important thing to consider is that the subscript should not go out of range. Turbo Pascal would give no error if the subscripts are wrong.

 

If you use a wrong subscript or did not maintain the proper value for the subscript the only thing you would see is that the values printed or calculated will be wrong. Wrong cell number, retrieve data from the wrong cell and calculations will be performed with the wrong data and therefore you will get wrong results.

 

The program shows the array being accessed on 3 different occasions. The first one shows how values may be stored in the array by accepting input from the user ( ReadLn( Numbers[ I ] ) ). The next is how the items stored in the array is being printed ( Write( Numbers[ I ]:5 ) ) and the last is the items in the array used as the incrementing value for the accumulator SUM ( Sum := Sum + Numbers[ I ] ).

 

The subscript used ( I ) is an integer and the value is generated by a FOR..DO loop which executes 10 times ( for I := 1 to 10 do ). This method is easy to apply because the subscript is generated automatically by the loop and the whole array is accessed when the loop executes.

 

In later lessons and examples, we shall look at how to maintain array subscripts in a more flexible way.

 

Subscript types may be any ordered data type (ordinal).

 

Upon completion of the program above, you should remember the following:-

  1. An array is a collection of memory cells.
  2. Each separate cell is referenced by using a subscript.
  3. The subscripts can only be of ordinal types.
  4. Don't use wrong subscripts or your results will be wrong.
  5. How to declare an array and know what the declaration means.

 

Here is another example which uses arrays but this time the subscripts used are of the CHARacter type.

 

program UseCharacterSubscripts;

 

uses CRT;

 

type

LetterArray = array [ 'A'..'Z' ] of integer;

 

var

Letters : LetterArray;

Ch : char;

I : integer;

Sentence : string;

 

begin { main program }

 

ClrScr;

{ initialize the array }

for Ch := 'A' to 'Z' do

Letters[ Ch ] := 0;

-*

 

Write('Type in a sentence : ');

ReadLn( Sentence );

 

{ process the whole string - 1st to last character }

for I := 1 to length( Sentence ) do

begin

Ch := upcase( Sentence[ I ] );

if Ch in [ 'A'..'Z' ] then

Letters[ Ch ] := Letters[ Ch ] + 1;

end;

 

{ print out the frequency of letters in the string }

for Ch := 'A' to 'Z' do

if Letters[ Ch ] <> 0 then

Write( Ch,'=',Letters[ Ch ],' ' );

ReadLn;

end. { main program }

 

You can visualize the array to be like this :-

 

       

...

   

'A'

'B'

'C'

'D'

...

'Y'

'Z'

 

 

Note:

Contents of array is character but index or subscript value is integer.

 

The first loop (FOR CH := 'A' TO 'Z' DO) is used to initialize the array LETTERS. Since the array is declared with a CHARacter subrange, the subscripts used must be of CHARacter type too. If your name is a string, nobody can call you by your name using numbers. So, the cells in the array are referenced by CHARacters and therefore the subscripts must be characters.

 

The processing of the string is done character by character, from the first character to the last. Each character is checked. If the character is a letter of the alphabet (A to Z) then that same character is used as the subscript to reference to the array LETTERS. That memory cell is then incremented by 1, indicating that a letter of this kind has been encountered. Do you notice that all the memory cells in the array LETTERS are actually counters?

 

After the whole string is processed, another loop is executed to output the results of the count. If any of the cells still contains zero (no letter of this type in the string), it won't be output.

 

Arrays As Parameters.

 

Using arrays as parameters is quite simple. You just have to specify an array type in the formal parameter list and you can pass an array into the procedure or function. The same rules and regulations apply when passing arrays as parameters. You should pass parameters by reference into procedures when the values in the array need to be changed.

Here is an example:

 

program EmployeeSalaries;

 

uses CRT;

 

const

NumEmployees = 5;

TaxPercent = 0.065;

 

type

IntegerArray = array [ 1..NumEmployees ] of integer;

RealArray = array [ 1..NumEmployees ] of real;

StringArray = array [ 1..NumEmployees ] of string;

var

EmpNames : StringArray;

HoursWorked : IntegerArray;

HourlyRate : RealArray;

GrossPay, NetPay : RealArray;

TotalGross : real;

 

procedure GetEmployeeData (

var EmpNames : StringArray;

var Hours : IntegerArray;

var Rate : RealArray );

var

I : integer;

Confirm : char;

begin

for I := 1 to NumEmployees do

begin

ClrScr;

WriteLn('Employee Payroll.'); WriteLn;

repeat

WriteLn('Employee Number : ', I ); WriteLn('~~~~~~~~~~~~~~~~~~~~~~');

Write('Enter Employee Name : ');

ReadLn( EmpNames[ I ] ); WriteLn;

Write('Enter Hours Worked : ');

ReadLn( Hours[ I ] ); WriteLn;

Write('Enter Wage Per Hour : ');

ReadLn( Rate[ I ] ); WriteLn;

Write('Confirm Entry ? ');

ReadLn( Confirm );

Confirm := upcase( Confirm );

until Confirm = 'Y';

end;

end; { GetEmployeeData }

 

procedure GetGrossPay ( Hours : IntegerArray;

Rate : RealArray;

var Gross : RealArray );

var

I : integer;

begin

for I := 1 to NumEmployees do

Gross[ I ] := Hours[ I ] * Rate[ I ];

end; { GetGrossPay }

 

procedure GetNetPay ( Gross : RealArray;

var Net : RealArray );

var

I : integer;

begin

for I := 1 to numEmployees do

Net[ I ] := Gross[ I ] - ( Gross[ I ] * TaxPercent );

end; { GetNetPay }

 

function AccumulatePay ( Pay : RealArray ) : real;

var

I : integer;

TempTotal : real;

begin

TempTotal := 0.0;

for I := 1 to NumEmployees do

TempTotal := TempTotal + Pay[ I ];

AccumulatePay := TempTotal;

end; { AccumulatePay }

 

procedure PrintResults ( Names : StringArray;

Gross, Net : RealArray;

TotalGross : real );

var

I : integer;

begin

ClrScr;

WriteLn( ' Employee Names ','':20,

'Gross Pay','':10,' Net Pay');

for I := 1 to NumEmployees do

WriteLn( Names[ I ]:30,'':20,

Gross[ I ]:9:2,'':10, Net[ I ]:9:2 );

WriteLn;

WriteLn('Total Gross Pay is RM', TotalGross:4:2);

end; { PrintResults }

 

begin { main program }

ClrScr;

GetEmployeeData(EmpNames, HoursWorked, HourlyRate );

GetGrossPay(HoursWorked,HourlyRate, GrossPay );

GetNetPay ( GrossPay, NetPay );

TotalGross := AccumulatePay( GrossPay );

PrintResults ( EmpNames, GrossPay, NetPay, TotalGross );

ReadLn;

end. { main program }

 

The important points to look at is the arrays which are used and what values are to be stored in them, the procedures and functions and what they are supposed to do and the parameters passed into these procedures. Of course, the subscripts are important.

 

The GETEMPLOYEEDATA procedure's parameters are all passed by reference because the names, hours worked and hourly rates of each employee is needed for future processing and output.

 

GETGROSSPAY procedure has 2 parameters passed by value. HOURSWORKED and HOURLYRATE are passed in this way because the values are left unchanged after the procedure completes execution. The procedure just needs these values to obtain the GROSSPAY. The GROSSPAY is passed by reference because the gross pay of each employee is needed later by another procedure to calculate the pay after tax deductions.

 

Procedure GETNETPAY accepts GROSSPAY as a value parameter and calculates and outputs the results through the array NETPAY which is passed by reference.

 

The function ACCUMULATEPAY adds up all the GROSSPAY values and returns the total gross pay. If the NETPAY array is passed into the procedure, it will be able to accumulate the net pay and return a total. The arrays EMPNAME, GROSSPAY, NETPAY and the variable TOTALGROSS is used later as parameters to PRINTRESULTS which displays the employees' names, gross pay, net pay and the grand total of the gross pay.

 

Two dimensional arrays.

 

Two dimensional arrays have not one but two subscripts and this can be visualized as a grid. Each position of the grid is referenced by two co-ordinates. You can imagine a point in a graph. The point is always referenced by two co-ordinates. Every location on the EARTH itself can be referenced by two co-ordinates. Latitude and longitude. Consider this program:

 

program TwoDimensionalArray;

uses CRT;

const

MaxStudents = 5;

type

TwoDimScores = array [ 1..MaxStudents, 1..3 ] of real;

NameArray = array [ 1..MaxStudents ] of string;

var

Scores : TwoDimScores;

Names : NameArray;

 

procedure GetData ( var Names : NameArray;

var Scores : TwoDimScores );

var

Row, Col : integer;

begin { GetData }

for Row := 1 to MaxStudents do

begin

Write( Row:10,') Student Name : ');

ReadLn( Names[ Row ] );

for Col := 1 to 3 do

begin

Write('':10,'Score ',Col,' : ' );

ReadLn( Scores[ Row, Col ] );

end;

WriteLn;

end;

end; { GetData }

 

function Grade ( Score : real ) : string;

begin { Grade }

if Score >= 70 then

Grade := 'Distinction'

else if Score >= 60 then

Grade := 'Credit'

else if Score >= 45 then

Grade := 'Pass'

else

Grade := 'Fail';

end; { Grade }

 

procedure DisplayResults (

var Names : NameArray;

var Scores : TwoDimScores );

var

Row, Col : integer;

Sum, Avg : real;

begin { DisplayResults }

ClrScr;

for Row := 1 to MaxStudents do

begin

Sum := 0.0; Avg := 0.0;

WriteLn('':10,'Name : ', Names[ Row ] );

for Col := 1 to 3 do

Sum := Sum + Scores[ Row, Col ];

Avg := Sum / 3;

WriteLn('':10,'Average score : ', Avg:4:2 );

WriteLn('':10,'Grade : ', Grade( Avg ) );

Write('':10,'Press <ENTER> to view next', 'results...');

ReadLn; WriteLn;

end;

end; { DisplayResults }

 

begin { main program }

ClrScr;

WriteLn('Student grading program.');

WriteLn('~~~~~~~~~~~~~~~~~~~~~~~~');

WriteLn;

GetData( Names, Scores );

DisplayResults( Names, Scores );

ReadLn;

end. { main program }

 

Notice how the SCORES array is referenced. Two subscripts are used. One to reference to the ROW and the other to the COLumns of the array. These are just views given to the array. How the computer actually stores the values need not be known. If you can visualize the array to be a 5 by 3 grid, then you can easily see why two subscripts are needed to reference to one cell in the array.

 

NAMES

 

 
 
 
 
 

 

SCORES

     
     
     
     
     

 

Again, as when dealing with one dimensional arrays, the subscript is the most important thing. This time there are two subscripts so extra care must be taken when writing the program.

 

Try to draw the array and 'see' what values are stored in the array at certain times in the program. You must be able to trace the destinations of each of the values as they are inserted into the array. If you can 'see' where the values are stored, you should be able to determine how the subscripts contribute to the storage of the items in the array. You can use subscripts of different types. You can use one character subscript and an integer subscript to reference to a two dimensional array.

Another thing you might find useful is array constants. These are arrays which are declared under the constant heading and have values assigned to each individual cell before the program execution starts.

 

Here is an example:

 

program ArrayConstants;

uses CRT;

const

Days : array [ 1..7 ] of string[ 12 ] =

( 'Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' );

var

I : integer;

begin { main program }

ClrScr;

for I := 1 to 7 do

WriteLn('Day : ',I,' = ', Days[ I ] );

ReadLn;

end. { main program }

 

If tracing is to be done, the values stored in the array would be :

 

DAYS

[1]

MONDAY

[2]

TUESDAY

[3]

WEDNESDAY

[4]

THURSDAY

[5]

FRIDAY

[6]

SATURDAY

[7]

SUNDAY

This program will simply print the contents of all the array cells (for I := 1 to 7 do). The contents of each cell is already pre-set in the declaration section. The first value in the list of values will be stored in the first cell of the array and the second value goes to the second cell and so on. The number of values in the value list must match the number of cells the array declared.

 

 

Typed constants are actually variables.

The values in the array DAYS can be changed if one wishes it so. Let's say a statement in the program says - DAYS[ 2 ] := 'MYDAY'; - the second cell of the array would then contain the value 'MYDAY'.

 

So, even if the values are initialized under the constant declaration, it can be changed during program execution. Even so, array constants are very useful. They are most used when the array needs to be initialized using values which cannot be generated using a loop.

 

Examples would be initializing the array with the days of the week, the months in a year, the number of days in a month for a year, the point ratio in a diving event (different difficulty levels are calculated using different point ratios), foreign exchange rates, different values to be used for testing a certain formula etc.

 

Remember, array constants are still arrays and the main use would still be to store data but use them only if you have to initialize the array with values which cannot be generated using a loop. Also remember that the values in array constants can be changed during program execution. In the case when the month of February has 29 days on a leap year, the ability to change the days in the array would be useful.

 

Here are some of the above mentioned examples (declarations only)

 

const

Months : array [1..12] of string[12] =

( 'January', 'February', 'March', 'April', 'May',

'June', 'July', 'August', 'September', ‘October','November', 'December' );

 

DaysInMonth : array [1..12] of integer =

( 31,28,31,30,31,30,31,31,30,31,30,31 );

 

 

Even two dimensional arrays can be declared as array constants. Here is a program which stores values in a two-dimensional array constants and outputs the contents:

 

program TwoDimConstants;

uses CRT;

const

TwoDim : array [ 1..3, 1..4 ] of integer =

((11,12,13,14),(21,22,23,24),(31,32,33,34));

var

Row, Col : integer;

begin { main program }

ClrScr;

for Row := 1 to 3 do

begin

Write('Row ', Row,' = ');

for Col := 1 to 4 do

Write( TwoDim[ Row,Col ]:6 );

WriteLn;

end;

ReadLn;

end.{ main program }

 

When reading the declaration, please be careful as the values in the array can be easily misread. If you run this program you will see these results:

 

Row 1 =11 12 13 14

Row 2 =21 22 23 24

Row 3 =31 32 33 34

 

Check the subscript value each time the array is referenced and you will know which cell in the array is accessed and it would be easier to figure out why it is accessed this way.