How to delete elements by using recursion? - ada

In this code, I have built a list of three integers (5, 10, 15) and what I need help with is that I need to ask the user which of these elements he/she wants to remove and then only return the element/elements that are left. I need to write a subprogram for this and just by using recursion, I need to remove the elements that the user does not need.
Main program:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Linked_List; use Linked_List;
procedure Main_Remove is
I : Integer;
L : List_Type;
begin
Build_Test_List(L); -- builds a list of 3 integers (5 => 10 => 15)
Put(L);
Put("Which elements do you want to remove/delete ");
Get(I);
Remove(L, I);
Put(L);
end Main_Remove;
Package:
package Linked_List is
type List_Type is private;
procedure Put(Item : in List_Type);
procedure Build_Test_List(Item : out List_Type;
Base : in Integer := 5);
private
type E_Type;
type List_Type is access E_Type;
type E_Type is
record
Data : Integer;
Next : List_Type;
end record;
end Linked_List;
Pakage body:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Unchecked_Deallocation;
package body Linked_List is
procedure Put(Item : in List_Type) is
P : List_Type := Item;
begin
Put("Listan: ");
while P /= null loop
if P /= Item then
Put(" -> ");
end if;
Put(P.Data, Width => 0);
P := P.Next;
end loop;
New_Line;
end Put;
procedure Insert_First(L : in out List_Type;
D : in Integer) is
begin
L := new E_Type'(Data => D, Next => L);
end Insert_First;
procedure Build_Test_List(Item : out List_Type;
Base : in Integer := 5) is
begin
for I in reverse 1..3 loop
Insert_First(Item, Base * I);
end loop;
end Build_Test_List;
end Linked_List;

Something like this will do, with reservations: specifically, there’s a memory leak.
procedure Remove (L : in out List_Type; Item : Integer) is
begin
The recursion has to be stopped when the list is empty.
if L = null then
return;
end if;
The list isn’t empty. What to do next depends on whether the current list element contains the value we’re looking for, or not.
if L.Data = Item then
This item needs to be removed from the list. Do this by altering the original pointer (which came from the list head, or the previous element) to skip over this element, and then process that element.
This is the point at which the memory leak has occurred. Obviously the cell being pointed to by the initial L needs to be freed, but you’re going to have to be careful about the order of operations.
L := L.Next;
Remove (L, Item);
else
The item stays in the list, go on to the next element.
Remove (L.Next, Item);
end if;
end Remove;

Related

How do I update an element in a this vector?

I am trying to update an element in a vector. I have quite a few issues that I don't know how to solve. When I use Replace_Element, everything works, but I want to use the proper procedure.
This is my code:
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
function TestUpdate(n : Node; val : Integer) return Node is
begin
n.Size := n.Size + val;
return n;
end TestUpdate;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
begin
Current_Node.Size := 10;
Nodes.Append(Current_Node);
NodeVector.Update_Element(Nodes, 0, TestUpdate'Access(5));
--NodeVector.Update_Element(Nodes, 0, TestUpdate'Access);
end Test_Update;
These are the errors that I am getting, and I know what is causing them, but no idea how to fix them:
test_update.adb:11:09: error: assignment to "in" mode parameter not allowed
test_update.adb:28:59: error: unexpected argument for "Access" attribute
When I use the code in the comments, and remove the second parameter for the function, it still doesn't work.
You have a lot of things mixed up here. First if you look at Zerte's answer more carefully than before, you'll notice that your TestUpdate operation doesn't match that Process argument at all. It expects a procedure (you have a function) and the procedure's parameter is "in out" while you are using "in" and you have an additional parameter. You need to fix this first
If you want to use Update_Element (I don't recommend it for your specific case) then you need to look into "Nested Subprograms". Here is an example of how to change your TestUpdate operation to work with Update_Element:
procedure TestUpdate(V : in out NodeVector.Vector; val : Integer) is
procedure Actual_Update(N : in out Node) is
begin
n.Size := n.Size + val;
end Actual_Update;
begin
V.Update_Element(V.Last,Actual_Update'Access);
end TestUpdate;
Notice how the Actual_Update procedure actually matches the process argument of the Update_Element operation contract. Additionally, since Actual_Update is nested, it has access to the Val argument from TestUpdate.
Full example:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
procedure TestUpdate(V : in out NodeVector.Vector; val : Integer) is
procedure Actual_Update(N : in out Node) is
begin
n.Size := n.Size + val;
end Actual_Update;
begin
V.Update_Element(V.Last,Actual_Update'Access);
end TestUpdate;
begin
Current_Node.Size := 10;
Nodes.Append(Current_Node);
TestUpdate(Nodes, 5);
end Test_Update;
With Vectors, you can also just index things directly. After you append an item, you can use <vector_name>.Last to get the cursor (index) for the last element...the one you just added. Example:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
procedure Using_Cursors
(V : in out NodeVector.Vector;
N : Node;
Value : Integer)
is begin
Nodes.Append(N);
Nodes(Nodes.Last).Size := Nodes(Nodes.Last).Size + Value;
end Using_Cursors;
begin
Current_Node.Size := 10;
Using_Cursors(Nodes,Current_Node,5);
end Test_Update;
A quick Web search will lead you to...
A.18.2 The Package Containers.Vectors
(or, if you use GNAT Studio: right-click on "Vectors" in "Ada.Containers.Vectors", then choose Go To Declaration).
Then you will find this:
procedure Update_Element
(Container : in out Vector;
Index : in Index_Type;
Process : not null access procedure
(Element : in out Element_Type));

How can you store (an access to) Integer's operators in Ada?

In Ada, the context can determine that "+" is not a String but an integer operator, as in the expression: "+"(5,2). The question is, how do I store that operator in a variable? I want to pass that integer operator, or some other one, as a binary function taking two Integers and returning an Integer. In the code below, I made an explicit function that just calls the operator, which I can use as a workaround. Is there some way to avoid having this wrapper, and pass around (an access to) Integer's "+" operator directly?
with Ada.Text_IO; use Ada.Text_IO;
procedure operator is
type binary_int_operator is access function(lhs : Integer; rhs : Integer) return Integer;
--plus : binary_int_operator := Integer."+"'Access;
--plus : binary_int_operator := Integer'Access("+");
--plus : binary_int_operator := Integer'"+";
--plus : binary_int_operator := "+";
function plus(lhs : Integer; rhs : Integer) return Integer is
begin
return lhs + rhs;
end plus;
begin
Put_Line(Integer'Image("+"(5, 12)));
end operator;
The commented declarations show some attempts I made, which do not compile.
I'm afraid you can't do that. The "+" subprogram for Integer is defined in the package Standard [ARM A.1 (17)] and therefore intrinsic [AARM A.1 (2.a)]. It's not allowed to reference an intrinsic subprogram [ARM 3.10.2 (32.3)]. Hence, compiling the program
procedure Main is
type Binary_Int_Operator is
access function (lhs : Integer; rhs : Integer) return Integer;
Plus : Binary_Int_Operator := Standard."+"'Access;
begin
null;
end Main;
yields
6:34 prefix of "Access" attribute cannot be intrinsic
The only workaround is using an indirection. This program compiles
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main_Alt is
type Operation is
access function (Lhs, Rhs : Integer) return Integer;
-- Sticking to "+" and "-" instead of names like Add or Subtract
-- to demonstrate that you can reference operator subprograms
-- (using the Access attribute) as long as they're not intrinsic.
function "+" (Lhs, Rhs : Integer) return Integer is
(Standard."+" (Lhs, Rhs));
function "-" (Lhs, Rhs : Integer) return Integer is
(Standard."-" (Lhs, Rhs));
procedure Calc_And_Show (Lhs, Rhs : Integer; Op : Operation) is
begin
Put (Op (lhs, rhs));
New_Line;
end Calc_And_Show;
begin
Calc_And_Show (5, 3, "+"'Access);
Calc_And_Show (5, 3, "-"'Access);
end Main_Alt;
and yields (as expected)
$ ./main_alt
8
2
I would suggest considering a different approach using generics.
Generally, I think you end up with a simpler interface for the call then you
get trying to pass in access to subprogram parameters.
(i.e. no need to pass the operation for each call).
Using generics, you don't need to use 'Access at all, and you can pass intrinsic functions such as integer "+", as formal generic parameters.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
generic
with function Op (L, R : Integer) return Integer;
procedure Calc_And_Show (Lhs, Rhs : Integer);
procedure Calc_And_Show (Lhs, Rhs : Integer) is
begin
Put (Op (lhs, rhs));
New_Line;
end Calc_And_Show;
procedure Calc_And_Show_Plus is new Calc_And_Show (Op => "+");
procedure Calc_And_Show_Minus is new Calc_And_Show (Op => "-");
begin
Calc_And_Show_Plus (5, 3);
Calc_And_Show_Minus (5, 3);
end Main;
There might be reasons why you'd want to use access parameters instead, such as if you wanted Calc_And_Show to be callable from other languages such as C, or if you are in a nested level of code and all you have passed to your nested level is an access to subprogram value. But I think it's generally a good idea to otherwise use generics or at least consider that option as a first preference, unless you have good reason not to.

Ada protected Put procedure doesn't write in the same line

My problem is that I created a protected Safe_Printer; but when I use it's procedure, it messes up the Put function. Every time it prints to a new line. How could I prevent this? Basically, I would like to print my matrix with it in a readable format.
Here is my code:
with Ada.Text_IO;
use Ada.Text_IO;
procedure main is
type Matrix is array(integer range <>, integer range <>) of integer;
protected Safe_Printer is
procedure Put(S: String);
procedure Put(M: Matrix);
end Safe_Printer;
protected body Safe_Printer is
procedure Put(S: String) is
begin
for I in S'range loop
Put(S(I));
end loop;
New_Line;
end Put;
procedure Put(M:Matrix) is
begin
for I in m'range(1) loop
for j in m'range(2) loop
put(integer'image(m(i,j)) & " ");
end loop;
new_line(1);
end loop;
end Put;
end Safe_Printer;
m:Matrix := ((1,2,3),
(4,5,6));
begin
Safe_Printer.Put(m);
for I in m'range(1) loop
for j in m'range(2) loop
put(integer'image(m(i,j)) & " ");
end loop;
new_line(1);
end loop;
end main;
And my output is :
1
2
3
4
5
6
1 2 3
4 5 6
Because the 'Image attribute returns a String, your implementation of Put(M : Matrix) invokes Safe_Printer.Put(S : String) in its inner loop; each matrix entry then gets a New_Line. One solution is to call the language defined Put explicitly in Safe_Printer.Put(M : Matrix):
procedure Put(M : Matrix) is
begin
for I in M'range(1) loop
for j in M'range(2) loop
Ada.Text_IO.Put(integer'image(M(i,j)) & " ");
end loop;
New_Line;
end loop;
end Put;
As tested:
with Ada.Text_IO;
use Ada.Text_IO;
procedure main is
type Matrix is array(integer range <>, integer range <>) of integer;
protected Safe_Printer is
procedure Put(S : String);
procedure Put(M: Matrix);
end Safe_Printer;
protected body Safe_Printer is
procedure Put(S : String) is
begin
for I in S'range loop
Put(S(I));
end loop;
New_Line;
end Put;
procedure Put(M : Matrix) is
begin
for I in M'range(1) loop
for j in M'range(2) loop
Ada.Text_IO.Put(integer'image(M(i,j)) & " ");
end loop;
New_Line;
end loop;
end Put;
end Safe_Printer;
M : Matrix := ((1,2,3),
(4,5,6));
begin
Safe_Printer.Put(M);
end main;
Console:
$ ./main
1 2 3
4 5 6
Alternatively, as #SimonWright comments, you could "remove the New_Line in Safe_Printer.Put(String)." The approach you choose will depend on the desired effect offered in the Safe_Printer specification. Also consider limiting the scope of the use clause.
You should not call a 'potentially blocking operation' from within a protected object. The call to Text_IO.Put is a potentially blocking operation. See the Ada Reference Manual section 9.5.1. I am surprised your compiler didn't complain, actually.
One thing you can do in this situation is to use a task instead of a protected object.
For example:
with Ada.Text_IO;
procedure Main is
type Matrix is array (Integer range <>, Integer range <>) of Integer;
task Safe_Printer is
entry Put (S: in String);
entry Put (M: in Matrix);
end Safe_Printer;
task body Safe_Printer is
S: access String;
M: access Matrix;
begin
loop
select
accept Put (S: in String) do
Safe_Printer.S := new String (S'Range);
Safe_Printer.S.all := S;
end;
Ada.Text_IO.Put_Line (S.all);
or
accept Put (M: in Matrix) do
Safe_Printer.M := new Matrix (M'Range (1), M'Range (2));
Safe_Printer.M.all := M;
end;
for I in M'Range (1) loop
for J in M'Range (2) loop
Ada.Text_IO.Put (Integer'Image (M (I, J)) & " ");
end loop;
Ada.Text_IO.New_Line;
end loop;
or
terminate;
end select;
end loop;
end Safe_Printer;
M: Matrix := ((1,2,3),
(4,5,6));
begin
Safe_Printer.Put (M);
end Main;
An added advantage of this approach is that the calls to Text_IO.Put[_Line] are actually executed in parallel with the main task. A disadvantage is that (to be safe) the string or matrix to be printed is copied.
A better version of this code might use Unchecked_Deallocation or Ada.Containers.Indefinite_Holders to clean up after itself nicely.
Bonus question: What do you think the array bounds of the matrix M in the Main procedure are?

Getting variables from a line from a file

I was wondering if any of you could answer a quick question for me. I am currently working with records right now and in my program I need it to understand what the line of a file that i'm importing contains. My problem lies in the fact that I don't know how to "split" the line into actual variables. For example the line is
22134.09 Kia Bernice
How do I make the program know that the first part, 22134.09 is the variable price, Kia is the variable company and Bernice is the variable model, and then sort them all into a record?
Such as
type PriceCompModel is record
price : Float range 1.0..99999.99;
company : String (1..CompNameLength);
Model : String (1..ModelNameLength);
Thanks.
edited code
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Testexercise is
type Inventory is Record
CarPrice : Float := 0.0;
CarType : String (1..40);
-- CarType will include both the model and company
end record;
InventoryItem : Inventory;
ImportedFile : File_Type;
FileName : String := "Cars.txt";
WordsFromFile : String(1..40);
LengthofWords : Integer ;
PriceofCar : Float := 0.0;
LoopCount : Integer := 1;
type Cars is array (1..12) of Inventory;
begin
Open(File => ImportedFile, Mode => In_File, Name => FileName);
--for I in 1..12 loop
while LoopCount /= 12 loop
Get(File => ImportedFile, Item => InventoryItem.CarPrice);
Get_Line(File => ImportedFile, Item => WordsFromFile, Last=> LengthofWords);
Put (Integer(InventoryItem.CarPrice),1);
Put (WordsFromFile(1..LengthofWords));
New_Line;
LoopCount := LoopCount + 1;
InventoryItem.CarType := WordsFromFile;
end loop;
close(ImportedFile);
end Testexercise;
So i tried doing this within the loop
for I in 1..12 loop
Cars := Inventory;
end loop;
This ended up working for me after i set
Car : Cars;
for I in 1..12 loop
Car(I) := Inventory;
end loop;
You have many factors to consider when defining the record to contain your information.
It will be useful to create a named subtype of float, or a named floating point type so that the I/O routines can check the input values for the price component.
Fields of type String must be constrained to a predefined size. This means that all "company" strings must be the same size, and all "model" strings must be the same size, although model strings may be a different length than company strings. If the names of companies and/or models may vary then you should consider using either bounded strings (Ada Language Reference Manual section A.4.4) or unbounded strings (Ada Language Reference Manual section A.4.5).
If the strings of the input file are fixed in size you can use Ada.Text_IO.Text_Streams (Ada Language Reference Manual section A.12.2) to read each field of the record. If the strings can be different sizes then you will need to read and parse each field manually using Ada.Text_IO.
-- Read record data from a file
with Ada.Text_Io; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
procedure read_record is
type Prices is delta 0.01 digits 7 range 0.0..99999.99;
type Auto_Inventory is record
Price : Prices := 0.0;
Company : Unbounded_String := Null_Unbounded_String;
Model : Unbounded_String := Null_Unbounded_String;
end record;
package AI_IO is new Ada.Text_IO.Decimal_IO(Prices);
use AI_IO;
Inventory_Item : Auto_Inventory;
The_File : File_Type;
File_Name : String := "inventory.txt";
Inpt_Str : String(1..1024);
Length : Natural;
Start, Finis : Positive;
begin
Open(File => The_File,
Mode => In_File,
Name => File_Name);
Get(File => The_File,
Item => Inventory_Item.Price);
Get_Line(File => The_File,
Item => Inpt_Str,
Last => Length);
Close(The_File);
Start := Index_Non_Blank(Source => Inpt_Str(1..Length));
Finis := Start;
while Finis < Length and then Inpt_Str(Finis) /= ' ' loop
Finis := Finis + 1;
end loop;
Inventory_Item.Company := To_Unbounded_String(Inpt_Str(Start..Finis));
Start := Index_Non_Blank(Inpt_Str(Finis + 1..Length));
Inventory_Item.Model := To_Unbounded_String(Inpt_Str(Start..Length));
Put_Line("Price: " & Prices'Image(Inventory_Item.Price));
Put_Line("Company: " & To_String(Inventory_Item.Company));
Put_Line("Model: " & To_String(Inventory_Item.Model));
end read_record;
If you want to read a file containing many records you need to collect the information in some kind of container. The following example uses a Vector from the generic package Ada.Containers.Vectors.
-- Auto Inventory Package specification
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
package Auto_Inventory is
type Prices is delta 0.01 digits 7 range 0.0..99999.99;
type Automobile is tagged private;
procedure Print(Item : Automobile);
function Set return Automobile;
function Get_Price(Item : Automobile) return Prices;
function Get_Company(Item : Automobile) return String;
function Get_Model(Item : Automobile) return String;
type Inventory is tagged private;
procedure Read(Item : out Inventory; File : File_Type) with
Pre => Mode(File) = In_File;
procedure Write(Item : in Inventory; File : File_type) with
Pre => Mode(File) = Out_File;
procedure Print(Item : Inventory);
private
type Automobile is tagged record
Price : Prices := 0.0;
Company : Unbounded_String := Null_Unbounded_String;
Model : Unbounded_String := Null_Unbounded_String;
end record;
package Auto_Vect is new
Ada.Containers.Vectors(Index_Type => Positive,
Element_Type => Automobile);
use Auto_Vect;
type Inventory is tagged record
List : Vector;
end record;
end Auto_Inventory;
The body for this package is:
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
package body Auto_Inventory is
package Prices_IO is new Ada.Text_IO.Decimal_IO(Prices);
use Prices_IO;
-----------
-- Print --
-----------
procedure Print (Item : Automobile) is
use Prices_Io;
begin
Put_Line("Price : " & Prices'Image(Item.Price));
Put_Line("Company: " & To_string(Item.Company));
Put_Line("Model : " & To_String(Item.Model));
New_Line;
end Print;
---------
-- Set --
---------
function Set return Automobile is
Temp : Automobile;
Inpt_Str : String(1..1024);
Length : Natural;
begin
Put("Enter the automobile price: ");
Get(Item => Temp.Price);
Put("Enter the automobile company: ");
Get_Line(Item => Inpt_Str, Last => Length);
Temp.Company := To_Unbounded_String(Inpt_Str(1..Length));
Put("Enter the automobile model: ");
Get_Line(Item => Inpt_Str, Last => Length);
Temp.Model := To_Unbounded_String(Inpt_Str(1..Length));
return Temp;
end Set;
---------------
-- Get_Price --
---------------
function Get_Price (Item : Automobile) return Prices is
begin
return Item.Price;
end Get_Price;
-----------------
-- Get_Company --
-----------------
function Get_Company (Item : Automobile) return String is
begin
return To_String(Item.Company);
end Get_Company;
---------------
-- Get_Model --
---------------
function Get_Model (Item : Automobile) return String is
begin
return To_String(Item.Model);
end Get_Model;
----------
-- Read --
----------
procedure Read (Item : out Inventory;
File : File_Type) is
Temp : Inventory;
Auto : Automobile;
Inpt_Str : String(1..1024);
Length : Natural;
Start, Finis : Positive;
begin
while not End_Of_File(File) loop
Get(File => File, Item => Auto.Price);
Get_Line(File => File, Item => Inpt_str, Last => Length);
Start := Index_Non_Blank(Inpt_Str(1..Length));
Finis := Start;
while Finis < Length and then Inpt_Str(Finis) /= ' ' loop
Finis := Finis + 1;
end loop;
Auto.Company := To_Unbounded_String(Inpt_Str(Start..Finis - 1));
Start := Index_Non_Blank(Inpt_Str(Finis..Length));
Auto.Model := To_Unbounded_String(Inpt_Str(Start..Length));
Temp.List.Append(Auto);
end loop;
Item := Temp;
end Read;
-----------
-- Write --
-----------
procedure Write (Item : in Inventory;
File : File_type) is
begin
for Element of Item.List loop
Put(File => File, Item => Prices'Image(Element.Price) &
" " & To_String(Element.Company) & " " &
To_String(Element.Model));
New_Line;
end loop;
end Write;
-----------
-- Print --
-----------
procedure Print (Item : Inventory) is
begin
for Element of Item.List loop
Element.Print;
end loop;
end Print;
end Auto_Inventory;
An example of a main procedure to exercise this package:
------------------------------------------------------------------
-- Read a file of many records --
------------------------------------------------------------------
with Auto_Inventory; use Auto_Inventory;
with Ada.Text_IO; use Ada.Text_IO;
procedure read_file is
The_Inventory : Inventory;
The_File : File_Type;
File_Name : String := "inventory.txt";
begin
Open(File => The_File,
Mode => In_File,
Name => File_Name);
The_Inventory.Read(The_File);
Close(The_File);
The_Inventory.Print;
end read_file;
An example input file for this program is:
22134.09 Kia Bernice
12201.15 Nissan Versa
22349.99 Chevrolet Cruse
It is not clear for me what language you are using .However the concept is to deal with each line from the file alone then process it with a function that do the token-zing or splitting depending on the language you use and save each token in a variable depending on how the function you are using will save the tokens
for example:
In java there is a class
StringTokenizer(String str, String delim)
StringTokenizer st = new StringTokenizer("this is a test", "$a; ");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
delim in your case is space so use the format
StringTokenizer st = new StringTokenizer("this is a test");
or
String line = reader.readLine();
String[] tokens = line.split("\\s");
note that you need to save the line you read in a string so you can use those functions in java then access each token from the array
String price = tokens[1] and so on
for other languages please find the following resources:
In c https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
In pyhton https://www.tutorialspoint.com/python/string_split.htm

dynamic array size determined at runtime in ada

Is it possible to have an array with size that is determined at runtime like so,
Procedure prog is
type myArray is array(Integer range <>) of Float;
arraySize : Integer := 0;
theArray : myArray(0..arraySize);
Begin
-- Get Array size from user.
put_line("How big would you like the array?");
get(arraySize);
For I in 0..arraySize Loop
theArray(I) := 1.2 * I;
End Loop;
End prog;
Is there a way to achieve this result other than using dynamically Linked Lists or another similar structure? Or is there a simple built in data structure that would be simpler than using dynamically linked lists?
Sure, declare it in a block as follows:
procedure prog is
arraySize : Integer := 0;
type myArray is array(Integer range <>) of Float;
begin
-- Get Array size from user.
put_line("How big would you like the array?");
get(arraySize);
declare
theArray : myArray(0..arraySize);
begin
for I in 0..arraySize Loop
theArray(I) := 1.2 * I;
end Loop;
end;
end prog;
or pass the arraySize as an argument into a subprogram and declare and operate on it in that subprogram:
procedure Process_Array (arraySize : Integer) is
theArray : myArray(0..arraySize);
begin
for I in arraySize'Range Loop
theArray(I) := 1.2 * I;
end Loop;
end;
This is just illustrative (and not compiled :-), as you need to deal with things like an invalid array size and such.
Yes, you can defer the declaration of a constrained object until you know the size. In this example, the array Candidates can be allocated in a nested block (introduced by the keyword declare) or on the heap (using the keyword new). In this related example, Line has a different size each time through the loop, depending on what Get_Line finds.

Resources