Previous | Next | Table of Contents | Index | Program List | Copyright

11.1 Data Structures: Unconstrained Array Types

The purpose of unconstrained array types is to allow subprograms that operate on arrays to be written without prior knowledge of the bounds of the arrays. Let us start with a type definition:

    TYPE ListType IS ARRAY (Integer RANGE <>) OF Float;
The construct Integer RANGE <> means that the subscript range, or bounds, of any variable of type ListType must form an integer subrange; the symbol "<>" is read "box" and means "we'll fill in the missing range when we declare ListType variables."

The type ListType is said to be unconstrained. When variables are declared, the compiler must know how much storage to allocate, and so each variable declaration must carry a range constraint, for example:

    L1 : ListType(1..50);    -- 50 elements
    L2 : ListType(-10..10);  -- 21 elements
    L3 : ListType(0..20);    -- 21 elements

Operations on Unconstrained Array Types

The operations of assignment and equality testing are defined for unconstrained array types, but for either operation to proceed without raising Constraint_Error, both operands must be variables of the same unconstrained array type and both operands must have the same number of elements. So

    L1 := L2;
will raise Constraint_Error, but the following operations will all succeed:
    L2 := L3;
    L1 (20..40) := L2;
    L2 (1..5) := L1 (6..10);
These slicing operations were introduced in Chapter 9 in the discussion of Ada strings. Ada's string type is actually defined in Standard as follows:
    TYPE String IS ARRAY (Positive RANGE <>) OF Character;
making strings just a special case of unconstrained arrays. The slicing operations work for all one-dimensional arrays just as they do for strings.

Attribute Functions for Unconstrained Arrays

Ada defines a number of attribute functions that can be used to determine the bounds of array variables. Given the type ListType above and the variable L2, L2'First returns the low bound of L2, or -10 in this case.

L2'Last returns the high bound of L2, or 10.

L2'Length returns the number of elements in L2, or 21.

L2'Range returns the range -10..10.

The last attribute is useful in controlling loops, for instance,

    FOR WhichElement IN L2'Range LOOP
      My_Flt_IO.Put(Item=>L2(WhichElement), Fore=>1, Aft=>2, Exp=>0);
      Text_IO.New_Line;
    END LOOP;
The construct L2'Range is a short way of writing L2'First..L2'Last, so the same fragment could be written
    FOR WhichElement IN L2'First..L2'Last LOOP
      My_Flt_IO.Put(Item=>L2(WhichElement), Fore=>1, Aft=>2, Exp=>0);
      Text_IO.New_Line;
    END LOOP;

Example 11.1

To show the utility of unconstrained arrays, consider a function to find the maximum value stored in an array of floating-point numbers. For this function to be generally useful and reusable, it needs to be able to work for all kinds of floating-point arrays, no matter what their bounds. Using the type ListType, Program 11.1 shows such a function contained in a test program. The program also contains a procedure DisplayList, which displays the contents of a ListType variable, whatever its bounds. The main program declares two lists of differing bounds, then displays the lists and tests the function MaxValue. From the output of the program, you can see that the maximum is found correctly even though the two lists have different sizes.

Program 11.1
A Demonstration of Unconstrained Arrays

WITH Ada.Text_IO;
WITH Ada.Float_Text_IO;
PROCEDURE Test_Max_Value IS
------------------------------------------------------------------------
--| Illustrates use of unconstrained array types
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: September 1995                                
------------------------------------------------------------------------

  TYPE  ListType IS ARRAY(Integer RANGE <>) of Float;

  L1 : ListType(1..5);     -- 5 elements
  L2 : ListType(-4..3);    -- 8 elements

  -- local procedure to display the contents of a list

  PROCEDURE DisplayList(L: ListType) IS
  -- Pre: L is defined
  -- Post: display all values in the list

  BEGIN -- DisplayList

    FOR Count IN L'Range LOOP
      Ada.Float_Text_IO.Put(Item=>L(Count), Fore=>3, Aft=>1, Exp=>0);
    END LOOP;
    Ada.Text_IO.New_Line;

  END DisplayList;


  FUNCTION MaxValue(L: ListType) RETURN Float IS
  -- Pre: L is defined
  -- Post: returns the largest value stored in L

    CurrentMax : Float;

  BEGIN -- MaxValue

    CurrentMax := Float'First;     -- minimum value of Float

    FOR WhichElement IN L'Range LOOP
      IF L(WhichElement) > CurrentMax THEN
        CurrentMax := L(WhichElement);
      END IF;
    END LOOP;
    -- assert: CurrentMax contains the largest value in L

    RETURN CurrentMax;

  END MaxValue;


BEGIN -- Test_Max_Value

  L1 := (0.0, -5.7, 2.3, 5.9, 1.6);
  L2 := (3.1, -2.4, 0.0, -5.7, 8.0, 2.3, 5.9, 1.6);

  Ada.Text_IO.Put(Item=> "Testing MaxValue for float lists");
  Ada.Text_IO.New_Line;
  Ada.Text_IO.New_Line;
  Ada.Text_IO.Put(Item=> "Here is the list L1");
  Ada.Text_IO.New_Line;
  DisplayList(L => L1);
  
  Ada.Text_IO.Put(Item=> "The maximum value in this list is ");
  Ada.Float_Text_IO.Put(Item => MaxValue(L=>L1), 
                Fore=>1, Aft=>2, Exp=>0);
  Ada.Text_IO.New_Line;
  Ada.Text_IO.New_Line;

  Ada.Text_IO.Put(Item=> "Here is the list L2");
  Ada.Text_IO.New_Line;
  DisplayList(L => L2);
  
  Ada.Text_IO.Put(Item=> "The maximum value in this list is ");
  Ada.Float_Text_IO.Put(Item => MaxValue(L=>L2), 
                Fore=>1, Aft=>2, Exp=>0);
  Ada.Text_IO.New_Line;

END Test_Max_Value;
Sample Run
Testing MaxValue for float lists

Here is the list L1
  0.0 -5.7  2.3  5.9  1.6
The maximum value in this list is 5.90

Here is the list L2
  3.1 -2.4  0.0 -5.7  8.0  2.3  5.9  1.6
The maximum value in this list is 8.00

SYNTAX DISPLAY
Unconstrained Array Type

Form:
TYPE ArrayType IS ARRAY (IndexType RANGE <>) OF ValueType ;

Example:
SUBTYPE DaysInYear IS Positive RANGE 1..366;
SUBTYPE Temperature IS Float RANGE -100.0 .. 200.0;
TYPE TemperatureReadings IS 
  ARRAY (DaysInYear RANGE <>) OF Temperature;

Interpretation:
The array type is declared with minimum and maximum bounds given by IndexType. The actual bounds of an array variable must be supplied, as a subrange of IndexType, when that variable is declared. It is therefore illegal to declare

Temps: TemperatureReadings;
Rather, the declaration must include bounds:

Temps: TemperatureReadings (1..31);

Slicing and Unconstrained Arrays

In Section 9.1 we studied array slicing in the context of strings. Slicing is actually more general: It is available for all one-dimensional unconstrained arrays in Ada. For example, given the function MaxValue from Program 11.1 and a Float variable Y, it is permissible to call MaxValue with a slice as its parameter, as in

    Y := MaxValue(L => L2(0..2));
which would search only the given slice of the array for a maximum value. As an exercise, you can modify Program 11.1 to test this concept.

Exercises for Section 11.1

Programming

  1. Modify Program 11.1 to call MaxValue with parameters L1(2..4), L2(0..2), and L2(-4..-1) and ascertain that the program correctly finds the given maximum values.


Previous | Next | Table of Contents | Index | Program List | Copyright

Copyright © 1996 by Addison-Wesley Publishing Company, Inc.