问题
Im working on a problem where I need to make a set of boxes according to an input number where each and every box has a unique name. I've managed to create the boxes but I've only managed to insert one name on all of them as my names are overwritten in the name collecting procedure.
here is the code https://pastebin.com/FBMvvrn4
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure exercise is
N : Integer;
Names : String(1..10);
L : Integer;
procedure Objectcatcha (N: out Integer) is
begin
Put("Enter amount of objects: ");
Get(N);
end Objectcatcha;
procedure Namescatcha (Names: out string; L: out integer) is
begin
for I in 1..N loop
Get_Line(Names, L);
end loop;
end Namescatcha;
procedure SpaceBox(Names: in String; L: in Integer; N : in integer) is
begin
for I in 1..N loop
Put("+-----------+ ");
end loop;
New_Line;
for I in 1..N loop
Put("! ");
Put(Names(1..L));
for J in (L+1)..10 loop
Put(" ");
end loop;
Put("!");
if I = N then
Put("");
else
Put("<>---");
end if;
end loop;
New_Line;
for I in 1..N loop
Put("+-----------+ ");
end loop;
end SpaceBox;
begin
Objectcatcha(N);
Put("Enter the name of the objects: ");
Namescatcha(Names, L);
SpaceBox(Names,L, N);
end exercise;
I've been sitting around a lot with this and Id be very glad if someone could help me find a way to name each box individually.
Thanks in advance!
回答1:
Where you can, (and you can here), just declare a variable of the exact size to hold the name you are using. This can be done by declaring it as an indefinite array, and initialising it with the correct name.
So your main program could be:
Objectcatcha(N);
For I in 1 to N loop
Put("Enter the name of the next object: ");
Declare
Name : String := Namescatcha;
Begin
SpaceBox(Name, Name'Length, N);
End;
End loop;
Namescatcha is now a function returning just the right size of string:
function Namescatcha return String is
begin
return Getline;
end Namescatcha;
and you should probably rewrite Spacebox without L (you can always use Name'Length to see the length of Name)
回答2:
Brian Drummond already covered how to get back a variable length name and some means to work with them. In order to address your one name overwriting all the names problem, you have to consider that you are using one name variable to hold them all so it makes sense that one is overwriting the others. To store multiple names together, consider using an Indefinite_Vector to hold them. In your Objectcatcha procedure you get the capacity so use that to set the size of the vector
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Vectors; use Ada.Containers;
-- Other stuff
package Name_Vectors is new Indefinite_Vectors
(Index_Type => Positive,
Element_Type => String);
Names : Name_Vectors.Vector;
package Count_Type_IO is new Integer_IO(Count_Type);
procedure Objectcatcha is
Number : Count_Type;
Last : Positive; -- Placeholder for Get call
begin
Put("Enter amount of objects: ");
Count_Type_IO.Get
(From => Get_Line,
Item => Number,
Last => Last);
Names.Reserve_Capacity(Number);
end Objectcatcha;
procedure Namescatcha is
begin
for Index in 1..Names.Capacity loop
Names.Append(Get_Line);
end loop;
end Namescatcha;
You will need to adjust your SpaceBox procedure to use the vector instead of the name or to only do one name at a time (your choice).
A few notes: 1. I changed your Get call to Get_Line for getting the number of names, you can change it back if you want. 2. When I stored the names in the vector, the last character stored might be the "new line" character, so you may have to strip it out. That's easy to do. Just use all the characters of the name except the last one. for example:
EDIT: Simon Wright indicated that this shouldn't be needed. My implementation does, so I'll leave this here if you have a setup similar to what I tested on and the new lines are copied.
declare
Name : String := Names(Index);
begin
Put(Name(1..Name'Length-1));
end;
回答3:
Since your program seems to be a non-performance-critical application, I'd use variable-size strings to avoid storing the N different string lengths.
In plain Ada variable-size strings are called Unbounded_String
.
Here, your exercise using an open-source package (hac_pack: spec, body) which facilitates things around variable-size strings.
with HAC_Pack; use HAC_Pack;
procedure Names_in_Boxes is
Max : constant := 100;
type Names_Type is array (1 .. Max) of VString;
procedure Objectcatcha (N: out Integer) is
begin
Put("Enter amount of objects: ");
Get(N);
Skip_Line;
end Objectcatcha;
procedure Namescatcha (Names: out Names_Type; N : in Integer) is
begin
for I in 1..N loop
Put(+"Object " & I & ": ");
Get_Line(Names (I));
end loop;
end Namescatcha;
procedure SpaceBox(Names: in Names_Type; N : in Integer) is
begin
Put_Line (N * (+"+-----------+ "));
for I in 1..N loop
Put("! " & Names(I) & (10 - Length(Names(I))) * ' ' & "!");
if I = N then
Put("");
else
Put("<>---");
end if;
end loop;
New_Line;
Put_Line (N * (+"+-----------+ "));
end SpaceBox;
-- "Global" variables, unknown to
-- Objectcatcha, Namescatcha, SpaceBox:
N : Integer;
Names : Names_Type;
begin
Objectcatcha(N);
Put_Line("Enter the name of the objects: ");
Namescatcha(Names, N);
SpaceBox(Names, N);
end Names_in_Boxes;
回答4:
Thanks Zerte, Jere and Brian for your examples, it's much appreciated. Unfortunately I can't use third party packages so that rules out Zertes solution and as for Jere Im sorry but Im just a simple codemonkey with very shallow ADA knowledge and your example is just too complicated for me. Even if I got the exact code and it worked I still wouldnt learn it because it differs too much from what my school is teaching out. Like the procedures not having in/out parameters lets say for one. Maybe I misunderstand and its not that bad but at first glance it seems too complex for my level of ADA.
Brians I thought would work but what it does is, because it loops Spacebox N times, it creates N^2 amount of boxes, and on separate lines, when I only need N boxes on one line. Is there any way we could perhaps patch up the code to fix this because it seemed promising?
Thanks again for your time all of you!
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO; use Ada.Strings.Unbounded.Text_IO;
procedure exercise is
Y : Ada.Text_IO.Count;
N : Integer;
Names : Unbounded_string;
type Names_Type is array (Positive range <>) of Unbounded_String;
procedure Objectcatcha (N : out Integer) is
begin
Put("Enter amount of objects: ");
Get(N);
Skip_Line;
end Objectcatcha;
procedure Namescatcha (Names: out Names_Type; N : in Integer) is
begin
for I in Names'Range loop
Get_Line(Names(I));
end loop;
end Namescatcha;
procedure SpaceBox (Names: in Names_Type; N : in Integer) is
begin
for I in 1..N loop
Put("+-----------+ ");
end loop;
New_Line;
for I in Names'Range loop
Put("! ");
Put(Names(I));
Y := Ada.Text_IO.Count(I);
Set_Col(13+18*(Y-1));
Put("!");
if I = N then
Put("");
else
Put("<>---");
end if;
end loop;
New_Line;
for I in 1..N loop
Put("+-----------+ ");
end loop;
end SpaceBox;
begin
Objectcatcha(N);
declare
A : Names_Type (1..N);
begin
Put("Enter the name of the objects: ");
Namescatcha(A, N);
SpaceBox(A, N);
end;
end exercise;
This code works exactly the way I wanted it to, so I think it's finally solved: yay! :)
来源:https://stackoverflow.com/questions/61719343/storing-and-using-strings-of-varying-length-ada