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