Ada supports a number of attributes which can be used with respect to array:
where T is an identifier for either a type or a data item. This is unlike other Ada attributes which can only be associated with a type identifier.
Program to "load" an 8 element character array and the output the result. Program comprises four procedures/functions:
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
CHAR_ARRAY | Global variable | ARRAY_T | Default |
START_INDEX | Global constant | INTEGER | 1 |
END_INDEX | Global constant | INTEGER | 8 |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
CHAR_ARRAY | Formal out parameter | ARRAY_T | Default |
CHAR | Local input variable | CHARACTER | Default |
INDEX | Local variable | INTEGER | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
CHAR_ARRAY | Formal out parameter | ARRAY_T | Default |
LOOP_COUNT | Local variable | INTEGER | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
CHAR | Formal parameter | CHARACTER | Default |
CHAR_ARRAY | Formal out parameter | ARRAY_T | Default |
CURRENT_END | Formal parameter | INTEGER | Default |
The algorithms involved are described using the Nassi-Shneiderman charts presented below.
The implementation is as follows:
-- ARRAY_IO -- 3 December 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure ARRAY_IO is START_INDEX : constant := 1; END_INDEX : constant := 10; type ARRAY_T is array (START_INDEX..END_INDEX) of CHARACTER; CHAR_ARRAY : ARRAY_T; ---------------------------------------------------------------------------- -- INPUT ARRAY procedure INPUT_ARRAY(CHAR_ARRAY : in out ARRAY_T) is CHAR : CHARACTER; INDEX : INTEGER := ARRAY_T'FIRST ; ------------------------------------------------------------------------ -- CHECK FOR DUPLICATE function CHECK_FOR_DUPLICATE(CHAR : CHARACTER; N_ARRAY : ARRAY_T; CURRENT_END : INTEGER) return BOOLEAN is begin for INDEX in ARRAY_T'FIRST..CURRENT_END-1 loop if CHAR = N_ARRAY(INDEX) then RETURN(FALSE); end if; end loop; RETURN(TRUE); end CHECK_FOR_DUPLICATE; ------------------------------------------------------------------------ begin PUT_LINE("Input character array elements:"); while INDEX <= ARRAY_T'LAST loop GET(CHAR); if CHECK_FOR_DUPLICATE(CHAR,CHAR_ARRAY,INDEX) then CHAR_ARRAY(INDEX):=CHAR; INDEX:=INDEX+1; else PUT("ERROR: Duplicate input "); PUT(CHAR); NEW_LINE; end if; end loop; end INPUT_ARRAY; ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- -- OUTPUT ARRAY procedure OUTPUT_ARRAY(CHAR_ARRAY : ARRAY_T) is begin for INDEX in START_INDEX..ARRAY_T'LENGTH loop PUT(CHAR_ARRAY(INDEX)); PUT(" "); end loop; NEW_LINE; end OUTPUT_ARRAY; ---------------------------------------------------------------------------- -- TOP LEVEL begin INPUT_ARRAY(CHAR_ARRAY); OUTPUT_ARRAY(CHAR_ARRAY); end ARRAY_IO;
Ada supports a number of predefined operations on arrays.
if ARRAY_1 = ARRAY_2 then ... while ARRAY_1 /= ARRAY_2 then ...
ARRAY_1 := ARRAY_2
Ada also supports the concept of slices. A Slice is a sub-array of an array. The process of slicing returns a sub-array. Thus given:
IA: array (INTEGER range N..N+4) of INTEGER := (2,4,6,8,10);
The statement
IA_SUB = IA(N+1..N+3)
would assign the sub array (4,6,8) to IA_SUB (assuming this is declared appropriately).
Arrays can be thought of in terms of lists of elements (as used in declarative languages). As such we can identify a number of common list operations which we may wish to perform:
It is often necessary to carry out a particular operation on all the members of an array. This is called \fImapping, we map the desired operation onto the elements of the array. For example we may wish to cube all the elements of an integer array:
procedure MAP_CUBE(MY_ARRAY: ARRAY_T) is begin for LOOP_INDEX in ARRAY_T'FIRST..ARRAY_T'LAST loop PUT(MY_ARRAY(LOOP_INDEX)**3); NEW_LINE; end loop; end MAP_CUBE;
The process of running through a list and "keeping" only those elements which pass some test is referred to as filtering. For example identifying the odd numbers in an integer array:
procedure FILTER_ODD(MY_ARRAY: ARRAY_T) is ------------------------------------------------------------------- -- ODD NUMBER BOOLEAN FUNCTION function ODD_ELEMENT(ELEMENT: INTEGER) return BOOLEAN is if (ELEMENT rem 2) /= 0 then RETURN(TRUE); else RETURN(FALSE); end if; end ODD_ELEMENT; ------------------------------------------------------------------ begin for LOOP_INDEX in ARRAY_T'FIRST..ARRAY_T'LAST loop if ODD_ELEMENT(MY_ARRAY(LOOP_INDEX)) then PUT(MY_ARRAY(LOOP_INDEX)); NEW_LINE; end if; end loop; end FILTER_ODD;
Note that this assumes an array with elements of type integer.
The process of putting an operator between each pair of elements in an array to produce a single data item is called folding. For example adding up all the elements of a numeric array for the purpose of finding (say) an average value or a total value.
procedure AVERAGE(MY_ARRAY: ARRAY_T) is TOTAL: FLOAT; ------------------------------------------------------------------- -- FOLD TOTAL FUNCTION function FOLD_TOTAL(MY_ARRAY: ARRAY_T) return FLOAT is FOLD_TOTAL: FLOAT:=0; begin for LOOP_INDEX in ARRAY_T'FIRST..ARRAY_T'LAST loop FOLD_TOTAL := FOLD_TOTAL+MY_ARRAY(LOOP_INDEX) end loop; RETURN(FOLD_TOTAL); end FOLD_TOTAL; ------------------------------------------------------------------- begin TOTAL := FOLD_TOTAL(MY_ARRAY); PUT("Average = "); PUT(TOTAL/ARRAY_T'LENGTH, EXP=>0); NEW_LINE; end AVERAGE;Note that the above assumes an array with elements of type FLOAT.
The process of combining two arrays to form a third is called zipping. For example we may wish to "inter-leaf" the elements of two arrays.
procedure INTER_LEAF(MY_ARRAY_1, MY_ARRAY_2: in ARRAY_T; NEW_ARRAY: out ARRAY_BIG_T) is NEW_INDEX : INTEGER := 1; begin for INDEX in ARRAY_T'FIRST..ARRAY_T'LAST loop NEW_ARRAY(NEW_INDEX) := MY_ARRAY_1(INDEX); NEW_ARRAY(NEW_INDEX+1) := MY_ARRAY_2(INDEX); NEW_INDEX := NEW_INDEX+2; end loop; end INTER_LEAF;Note that the new array is returned using the out parameter passing mode.
Develop an Ada program which, given a set of six positive numbers,
determines the intersection
of this set with the set {1, 2, 3, 4, 5, 6}. Note: the input set
should contain no duplicates.
A top-down analysis of the proposed problem is given below.
We will represent both the base set and the user defined sets as arrays using a user defined array type SET_T defined as a 6 element array of type INTEGER. We can then identify the following procedures:
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
USER_SET | Local variable (array) | SET | n.a. |
SET_LENGTH | Local variable | INTEGER | Default |
SET_ELEMENT | Local variable | INTEGER | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
USER_SET | Formal parameter (array) | SET | n.a. |
BASE_SET | Local constant (array) | SET | {1, 2, 3, 4, 5, 6} |
USER_INDEX | Local variable | INTEGER | Default |
NAME | USAGE | TYPE | RANGE |
---|---|---|---|
USER_SET_SOFAR | Formal parameter (array) | SET | n.a. |
INPUT_ELEMENT | Formal parameter | INTEGER | Default |
LENGTH_SOFAR | Formal parameter | INTEGER | Default |
SET_INDEX | Local variable | INTEGER | Default |
RETURN_VALUE | Local variable | BOOLEAN | Default |
Complete Nassi-Shneiderman charts for the above are given below:
-- INTERSECTION -- 23 SEPTEMBER 1997 -- Frans Coenen -- Dept Computer Science, University of Liverpool with TEXT_IO; use TEXT_IO; procedure SET_INTERSECTION is START_INDEX : constant := 1; END_INDEX : constant := 6; package FLOAT_INOUT is new FLOAT_IO(FLOAT); use FLOAT_INOUT; package INTEGER_INOUT is new INTEGER_IO(INTEGER); use INTEGER_INOUT; type SET_T is array (START_INDEX..END_INDEX) of INTEGER; ----------------------------------------------------------------------------- -- INPUT_USER_SET function INPUT_USER_SET return SET_T is SET_LENGTH : INTEGER := START_INDEX; SET_ELEMENT : INTEGER; USER_SET : SET_T := (others => 0); ------------------------------------------------------------------------- -- NOT_DUPLICATE Boolean function function NOT_DUPLICATE(USER_SET_SOFAR: SET_T; INPUT_ELEMENT, LENGTH_SOFAR: INTEGER) return BOOLEAN is SET_INDEX : INTEGER := 1; RETURN_VALUE : BOOLEAN := TRUE; begin while SET_INDEX <= LENGTH_SOFAR loop if INPUT_ELEMENT = USER_SET_SOFAR(SET_INDEX) then PUT("Duplicate input ("); PUT(INPUT_ELEMENT, width=>1); PUT_LINE(")"); RETURN_VALUE := FALSE; SET_INDEX := LENGTH_SOFAR+1; else SET_INDEX := SET_INDEX+1; end if; end loop; RETURN(RETURN_VALUE); end NOT_DUPLICATE; ------------------------------------------------------------------------- begin PUT("Input a set "); PUT(END_INDEX-START_INDEX+1,width=>1); PUT(" (integer) elements: "); while SET_LENGTH <= END_INDEX loop GET(SET_ELEMENT); if NOT_DUPLICATE(USER_SET, SET_ELEMENT, SET_LENGTH-1) then USER_SET(SET_LENGTH) := SET_ELEMENT; SET_LENGTH := SET_LENGTH+1; end if; end loop; RETURN(USER_SET); end INPUT_USER_SET; ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- IDENTIFY_INTERSECTION procedure IDENTIFY_INTERSECTION(USER_SET : SET_T) is BASE_SET : constant SET_T := (1, 2, 3, 4, 5, 6); USER_INDEX : INTEGER := START_INDEX; begin PUT("Intersection = { "); for BASE_INDEX in START_INDEX..END_INDEX loop USER_INDEX := START_INDEX; while USER_INDEX <= END_INDEX loop if USER_SET(USER_INDEX) = BASE_SET(BASE_INDEX) then PUT(USER_SET(USER_INDEX), width=>1); PUT(" "); USER_INDEX := END_INDEX+1; else USER_INDEX := USER_INDEX+1; end if; end loop; end loop; PUT_LINE(" }"); end IDENTIFY_INTERSECTION; ----------------------------------------------------------------------------- -- INTERSECTION top level procedure begin IDENTIFY_INTERSECTION(INPUT_USER_SET); end SET_INTERSECTION;
BVA, Limit and Arithmetic Testing: Inputs may range from the maximum to the minimum default range for the integer type. We should also include a zero test value. A suitable set of black box test cases is given in the following table.
TEST CASE | EXPECTED RESULT |
---|---|
USER_SET | OUTPUT |
-2147483649 ... | DATA ERROR |
2147483648 ... | DATA ERROR |
-2147483648 -2147483647 0 2147483646 2147483647 1 | 1 |
Path Testing: We should test each path through the code. More particularly we should test where:
A suitable test USER_SET would then be of the form given below.
TEST CASE | EXPECTED RESULT |
---|---|
USER_SET | OUTPUT |
0 2 3 0 1 7 -2 | 2 3 1 |
Note that we replace the duplicate 0 with a 1.
This should also be done.
Example Problem Set Intersection.
Created and maintained by Frans Coenen. Last updated 11 October 1999