Arrays
Arrays: Overview
Array Variables, Bounds, Aggregates, Range Subtypes
Two Sample Programs
- printall.adb (prettified) - This program reads 10 integers and
prints them and their squares, forward and in reverse.
- printsome.adb (prettified) - This program reads 10 integers and
prints them and their squares, forward and in reverse.
Simple Array Declaration
- Declare an array variable:
procedure demo is
squares: array (1 .. 10) of integer;
begin
for i in 1 .. 10 loop
squares(i) := i ** 2;
end loop;
end demo;
Array Bounds are Flexible
- Array bounds can be any integers:
procedure demo is
squares: array (-10 .. 10) of integer;
begin
for i in -10 .. 10 loop
squares(i) := i**2;
end loop;
end demo;
Later we will see that other types of bounds are possible
Enumerated Types can be Array Bounds
- Enumerated types (not covered yet) can be array bounds:
procedure demo is
type days is (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
hours: array(Sunday .. Saturday);
subtype weekdays is days range Monday .. Friday;
work_hours: array(weekdays);
begin
...
end demo;
Later we will see that other types of bounds are possible
Aggregate Assignment
- An entire array can be assigned in one statement
procedure demo is
squares: array (1 .. 5) of integer;
begin
squares := (1, 4, 9, 16, 25); -- aggregate assignment
for i in 1 .. 10 loop
put(squares(i));
end loop;
end demo;
Note that the size of the aggregate must match the declaration
Aggregate Assignment with Keywords
- Can use indices to specify elements of array in the aggregate value
procedure demo is
values1: array (1 .. 50) of integer;
values2: array (1 .. 50) of integer;
values3: array (1 .. 50) of integer := (others => 0);
begin
values1 := (2 => 4, 4 => 16, 5 => 25, 3 => 9, others => 0); -- set remaining to 0
values2 := (others => 0); -- set all to 0
end demo;
Aggregate: Compared with Java
- Java uses the aggregate:
- only in the declaration
- aggregate defines the size:
int[] a = {1, 4, 9, 16, 25};
Java has a strange syntax:
// Does this compile? How big is the array?
int[] a = {1, 4, 9, 16, 25,}
Subtypes for Array Ranges
- Common to create a subtype for the array range
procedure demo is
min_int: constant := -10;
max_int: constant := 10;
subtype Int_Range is Natural range min_int .. max_int;
squares: array(int_range) of Natural;
cubes: array(int_range) of Natural;
begin
for i in int_range loop
squares(i) := i**2;
cubes(i) := i * squares(i);
end loop;
end demo;
Array Types, Attributes, and Looping
Array Types - Anonymous and Named
- squares and cubes each have an anonymous type
- An anonymous type has no name vs a named types
- Arrays with anonymous types are less flexible than with named types
- Can't pass array with anonymous type to a procedure
- Can't compare or assign two arrays with anonymous types
- More common to create a named array type
- Example:
procedure demo is
subtype int_range is Natural range 1 .. 10;
type IntArray is array(int_range) of Integer;
squares: IntArray;
cubes: IntArray;
begin
for i in int_range loop
squares(i) := i**2;
cubes(i) := i * squares(i);
end loop;
end demo;
Array Attributes
- Attributes of array variables and types:
- 'first
- 'last
- 'range
- 'length
- Attributes let us write code that is independent of the array bounds
- Example:
procedure demo is
subtype int_range is Natural range 2 .. 5;
type IntArray is array(int_range) of Natural;
squares: IntArray := (4, 9, 16, 25);
begin
put(IntArray'length);
for i in IntArray'first .. IntArray'last loop
put(squares(i));
end loop;
for i in IntArray'range loop
put(squares(i));
end loop;
put(squares'length);
for i in squares'first .. squares'last loop
put(squares(i));
end loop;
for i in reverse squares'range loop
put(squares(i));
end loop;
end demo;
Subtype Attributes
- Subtypes have attributes similar to array attributes:
- 'First, 'Last, 'Range
- But not 'Length, unfortunately
- 'Size is the size in bits, not the length
- Example:
procedure demo is
subtype Int_Range is Natural range 2 .. 5;
a: array(Int_Range) of natural;
begin
put(Int_Range'size);
for i in Int_Range'first .. Int_Range'last loop
put(i);
end loop;
for i in Int_Range'range loop
put(squares(i));
end loop;
-- Arrays, but not subtypes, have 'length
put(a'length);
-- put(Int_Range'length); -- Compile error
put(a'size); -- Size in bits
end demo;
Other Ways to Loop Over an Array
- Here are more ways to loop over an array
procedure demo is
subtype int_range is Natural range 2 .. 5;
type IntArray is array(int_range) of Natural;
squares: IntArray := (4, 9, 16, 25);
begin
-- Use int_range
for i in int_range'first .. int_range'last loop
put(squares(i));
end loop;
for i in int_range'range loop
put(squares(i));
end loop;
-- An iterator
for s OF squares loop
put(s);
end loop;
-- Calculate and output to the fourth paower
-- Use iterator in loop that modifies and printes each array element
for s OF squares loop
s := s * s;
put(s);
end loop;
end demo;
Advantages of Named Array Types
- Easy to make changes to your code
- Makes it possible to:
- Use arrays as procedure parameters
- Assign arrays
- Compare arrays
- Concatenate arrays
- Examples of these operations are below
Parameters of Array Type
- To pass an array as a parameter, you must use a named array type:
procedure demoArrayError is
-- Declare a new type
type IntArray is array (1 .. 10) of Natural;
procedure p(a: IntArray) is -- named type required
begin
put(a(1));
end p;
-- Declare a variable
myArray: IntArray;
begin -- demo
p(myArray);
end demoArrayError;
Error message - This statement:
procedure p(a: array(1..10) of integer) is
- causes this error: anonymous array definition not allowed here
Array Assignment, Comparison
- We can assign and compare two arrays
- Assignment and comparision on arrays requires the same named type:
with ada.text_io;
procedure demo is
package bool_io is new ada.text_io.enumeration_io(Boolean);
use bool_io; -- For printing boolean values
type IntArray is array(1 .. 5) of Natural;
squares: IntArray := (1, 4, 9, 16, 25);
cubes: IntArray := (1, 8, 27, 64, 125);
begin
put(squares = cube); -- False
put(squares < cube); -- False
put(squares <= cube); -- True
squares := cubes; -- A silly thing to do!
put(squares = cube); -- True
put(squares < cube); -- False
put(squares <= cube); -- True
end demo;
More on assignment and equality is below
Array Assignment and Equality Test: Reference and Value Types
Java Array Operations
- What happens with this Java code:
int[] a = {10, 20, 30};
int[] b = {10, 20, 30};
if (a == b) ... // T/F ?
b = a;
if (a == b) ... // T/F ?
b[0] = 99;
sop(a[0]); -- What is printed
if (a == b) ... // T/F ?
What does the memory allocation look like?
Array Assignment and Equality Tests
type Myarray is array (1 .. 3) of Integer;
a, b: Myarray;
...
a := (10, 20, 30);
b := (others => 0);
if a = b then ... -- T/F ?
b := a;
if a = b then ... -- T/F ?
b(1) = 99;
sop(a(1)); -- What is printed
if (a = b) ... // T/F ?
Equality test and assignment:
- Equality test and assignment are element by element
- Only allowed if both operands are of the same named type
Reference and Value Semantics
- For arrays we say that Ada has value semantics
- Ada has value semantics
- Java has reference semantics
- Meaning
- Assignment and equality operate on values vs references
- In Ada, an array variable holds an array value,
in Java an array variable holds a reference.
- Semantics refers to the meaning of a statement
- Also true for other structured types
- Java objects have reference sementics
- Ada records have value semantics
Filling the array using integer_text_io.Get (sumcountprocs2.adb)
Array Flexibility: Declare Blocks and Unconstrained Arrays
True or False?
- True or False:
- Java arrays are of fixed length: once set they can't be
changed
- Ada arrays are of fixed length: once set they can't be
changed
- Examples: ...
- But ...
True or False?
- A Java array is fixed length, but an array reference can
point to a different array
- An Ada array is fixed length, but ...
- the array can be allocated at runtime using a declare block
- we can create an Unconstrained Array Type:
- Bounds can be specified at runtime
- Useful for parameters
- Example: type String
Arrays with Fixed Bounds
- Problem: the array bounds we've seen are fixed at
COMPILE TIME and cannot be changed:
- An array variable cannot be redeclared as a different size:
a: is array(1 .. 10) of integer;
...
a: is array(1 .. 20) of integer; -- ERROR
Procedures only work for given type array
type ArrayType1 is array(1 .. 10) of integer;
type ArrayType2 is array(1 .. 20) of integer;
procedure putArray(a: ArrayType1) is
begin
...
end putArray;
a1: ArrayType1;
a2: ArrayType2;
begin
putArray(a1); -- Okay
putArray(a2); -- ERROR
How can we gain more flexibility:
- Passing the size as a procedure parameter
- Declaring the array in a declare/begin/end block
- With Unconstrained arrays
- Frequently used as parameters (very common)
Passing Array Size as a Parameter
procedure size_example(N: Natural) is
a: array(1 .. n) of integer
begin
for i in a'range loop
get(a(i));
end loop;
end declare_example;
Useful, but array a does not exist outside the procedure
Declare Blocks
- Variables can be declared anywhere - with a declare/begin/end block
- Example:
procedure declare_example is
size: natural;
begin
get(size);
declare
-- Length is fixed at runtime
a: array(1 .. size) of Integer;
begin
for i in a'range loop
get(a(i));
end loop;
-- do whatever you need to do with the array
end;
-- put(a'last); -- Error. Out of scope
end declare_example;
Scope of a is the declare block
Most things can be declared in a declare block, even other
preocedures (uncommon!)
Unconstrained Arrays
- Create an array type whose exact bounds are not fixed
- Allows postponing definition of exact bounds of an array
- Frequently used for passing arrays as parameters
- Example (Actual bounds must be a range of Naturals):
type IntArray is array(Natural range <>) of Integer;
myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
Type Intarray is Unconstrained
Variables myArray1 and myArray2 are Constrained
Variables must be constrained
- ie, myArray1: Intarray; -- Error
- We will see: Formal Parameters
can be Unconstrained!
Advantages of Unconstrained Arrays
- Variables of unconstrained types can be compared and
assigned:
- Because myArray1 and myArray2 have the same named type
procedure tryunc is
type IntArray is array(Natural range <>) of Integer;
myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
begin
if myArray1 = myArray2 then -- True or false?
put_line("same");
else
put_line("diff");
end if;
myArray2 := myArray1; -- Compile warning and RT error
end tryunc;
Unconstrained Arrays as Parameters
- Unconstrained arrays are very useful as parameters
procedure tryunc is
type IntArray is array(Natural range <>) of Integer;
function sumEmUp(a: IntArray) is
sum: Natural := 0;
begin
for i in a'range loop
sum := sum + a(i);
end loop;
return sum;
end sumEmUp;
myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
begin
put(sumEmUp(myArray1));
put(sumEmUp(myArray2));
end tryunc;
Allows declaring parameters that can be arrays of any size
- Attributes are useful (ie necessary!) to get the size
Declare Blocks and Unconstrained Arrays
- We can combine declare blocks and unconstrained arrays?
- Example:
with ada.text_io; with ada.integer_text_io;
use ada.text_io; use ada.integer_text_io;
procedure declare_example2 is
type My_Array_Type is array(Natural range <>) of Integer;
procedure put(a: My_Array_Type) is
begin
for i in A'range loop
put(a(i));
end loop;
end put;
size: natural;
begin
get(size);
declare
a: My_Array_Type(1 .. size);
begin
for i in a'range loop
get(a(i));
end loop;
put(a);
end;
end declare_example2;
Array Concatenation, Strings, and Array Slices
Concatenation
- & can concatenate any arrays (not just strings) of the
same named type
procedure tryunc is
type IntArray is array(Natural range <>) of Integer;
procedure put(a: IntArray) is
begin
for i in A'range loop
put(a(i));
end loop;
end put;
myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
begin
put(myArray1 & myArray2);
end tryunc;
Strings
- Strings are declared to be unconstrained arrays of characters
type String is array(Positive range <>) of Character;
Where is String declared?? Package Standard
Consider this:
procedure some_strings is
procedure put_reverse(s: String) is
begin
for i in reverse s'range loop
put(s(i));
end loop;
end put_reverse;
s1: String := "To";
s2: String := "Mom";
begin
if s1 = s2 then
put("Same, silly");
else
put_reverse(s1 & s2);
end if;
end some_strings;
More Information on Strings
- More information on Strings is here
Array Slices
- Any array can be sliced
- Slice = treat a subarray as an entire array!
- Example:
s: String := "Hi Mom!");
put(s(3 .. 5) & "?");
s(4) := 'T';
put(s);
s(4 .. 6) := "Bob";
put(s);
s(4 .. 4) := "R";
put(s);
Slices as Parameters
- We can pass a slice as a parameter
- Example:
procedure some_strings2 is
procedure put_reverse(s: String) is
begin
for i in reverse s'range loop
put(s(i));
end loop;
end put_reverse;
s: String := "Madam I'm Adam!");
begin
put_reverse(s);
put_reverse(s(2 .. s'last-2));
end some_strings2;
Strings are Mutable
- Strings are mutable
- Their values can change
- Obviously, because they are just arrays
- In contrast, Java strings are immutable
- Java Strings are NOT arrays of characters
- Pictures of execution show value semantics
A Little More on Array Slices
Multidimensional Arrays
Multidimensional Array
- Ada has true multidimensional arrays
- It also has arrays of arrays, which is like Java
- Some examples and discussion to come ...