PSlogo
homeicon uni sucheicon suche siteicon sitemap kontakticon kontakt
unilogo Universität Stuttgart
 

Institut für Softwaretechnologie

 

Get_Line nach Get

Es kommt häufig vor, dass zunächst eine Zahl gelesen wird und danach ein Text (String). Die Semantik der Unterprgrogramme aus den Ada Standardbibliotheken können hier überraschende Effekte haben.

Sämtliche Eingabe, die z.B. über die Tastatur eingegeben wird, wird zunächst zwischengespeichert. Aus Sicht eines Ada-Programms existiert also eine Sequenz verfügbarer Zeichen, die nacheinander aus dem Zwischenspeicher herausgenommen werden können. Leerzeichen, Zeilenumbrüche u.ä. (White Space) sind dabei ebenfalls Zeichen.

Semantik von Get

Die Prozedur Ada.Integer_Text_IO.Get liest aus der Eingabe solange White Space, bis eine Ziffernfolge kommt oder ein anderes Zeichen angetroffen wird und zu einem Lesefehler führt. Direkt nach dem Lesen der Ziffernfolge stoppt Get insbesondere bleibt also ein Zeilenumbruch direkt nach der Ziffenfolge in der Eingabesequenz.

Gibt ein Benutzer eine Zahl ein, so drückt er nach Ende der Eingabe die Return-Taste. Diese hat zur Folge, dass dieser abschließende Zeilenumbruch in die Eingabe gelangt (und nach Aufruf von Ada.Integer_Text_IO.Get dort auch bleibt)

Semantik von Get_Line

Die Prozedur Ada.Text_IO.Get_Line liest soviele Zeichen aus der Eingabe, bis entweder die übergebene String-Variable voll ist oder ein Zeilenumbruch gelesen wurde.

Problem

Da Ada.Integer_Text_IO.Get einen Zeilenumbruch in der Eingabe stehen lässt und Ada.Text_IO.Get_Line nur bis zum nächsten Zeilenumbruch liest, ist der von Get_Line zurückgegebene Text nur das Ende der Zeile hinter der Zahl.

Beispiel (falsch):
with Ada.Integer_Text_IO;
with Ada.Text_IO;

procedure Bad
is
   Buffer : String (1 .. 256);
   Last   : Natural;
   Num    : Integer;
begin
   Ada.Text_IO.Put ("Zahl: ");
   Ada.Integer_Text_IO.Get (Num);

   Ada.Text_IO.Put ("Text: ");
   Ada.Text_IO.Get_Line (Buffer, Last);

   Ada.Text_IO.Put_Line ("Gelesen (Zahl):" & Integer'Image (Num));
   Ada.Text_IO.Put_Line ("Gelesen (Text): " & Buffer (Buffer'First .. Last));
end Bad;

Eingabe:
123

Ablauf:
Zahl: 123
Text: Gelesen (Zahl): 123
Gelesen (Text):

Eingabe:
123 abcde

Ablauf:
Zahl: 123 abcde
Text: Gelesen (Zahl): 123
Gelesen (Text): abcde

Lösung

Um diesem Problem vorzubeugen sollte die Prozedur Ada.Text_IO.Skip_Line verwendet werden. Sie löscht Zeichen aus der Eingabe solange bis ein Zeilenumbruch gelöscht wird oder die Eingabe leer ist.
Beispiel (korrigiert):
with Ada.Integer_Text_IO;
with Ada.Text_IO;

procedure Good
is
   Buffer : String (1 .. 256);
   Last   : Natural;
   Num    : Integer;
begin
   Ada.Text_IO.Put ("Zahl: ");
   Ada.Integer_Text_IO.Get (Num);
   Ada.Text_IO.Skip_Line;

   Ada.Text_IO.Put ("Text: ");
   Ada.Text_IO.Get_Line (Buffer, Last);

   Ada.Text_IO.Put_Line ("Gelesen (Zahl):" & Integer'Image (Num));
   Ada.Text_IO.Put_Line ("Gelesen (Text): " & Buffer (Buffer'First .. Last));
end Good;

Eingabe:
123
abcde

Ablauf:
Zahl: 123
Text: abcde
Gelesen (Zahl): 123
Gelesen (Text): abcde

Eingabe:
123 xyz
abcde

Ablauf:
Zahl: 123 xzy
Text: abcde
Gelesen (Zahl): 123
Gelesen (Text): abcde