Coding Ada: get vs. get_line (ii) β some caveats
When used separately, get
and get_line
rarely cause issues. When used together, there can be some issues. Consider the following code:
a : integer; s : string(1..4); get(a); s := get_line; put(a); put_line(s);
Here is the dialog obtained when running the program containing this code:
4 raised CONSTRAINT_ERROR : testgetm.adb:14 length check failed
It allows the user to input the number 4, but then balks and pulls an exception. What went wrong? To see what happened we have to consider exactly what these input functions do. As we have seen, calls to get
for numeric and string input skip over blanks and line terminators that come before the number. Thatβs why it is possible to press the <return> key several times between numbers being entered. However these get
functions do not skip over any blanks and line terminators that come after the number. After the integer variable a
is read, the input pointer is set to the line terminator after 4.
Because get_line
stops reading when it encounters a line terminator, it stops and sets the length of the string to zero to indicate a null string. As the size of the (fixed) string is expected to be 4 characters in length, an exception is actioned. One way to circumvent this is to type the string on the same line as the number 4. For example:
6tool 6tool
This illustrates another feature of numeric input. The get
function for numeric data stops reading when a non-numeric character is encountered. The non-numeric character βtβ is not read and is still available to be read by the next call to an input function.
This solution is not really optimal. A better idea is to use the function skip_line
. When skip_line
is called, it moves the input pointer to the next line. It is most useful when using a get_line
function after getting a numeric value. Here is an example of its use:
a : integer; s : string(1..4); get(a); skip_line; s := get_line; put(a); put_line(s);
Note that if we use a unbound_string
instead of the fixed string, then the program will not convulse, but it also will skip the string input⦠but it will print out a string. Why? Well the unbound_string
will actually store the line terminator in the string⦠so it does read something, just not what it wanted.
To make things more consistent, it is also possible to read all input in as strings using get_line
, and convert the string to numbers. Below is an example of the code. The first value is input to the unbound_string
buf
, which is then converted to a string, and then an integer, and assigned to the integer variable a
.
a : integer; buf : unbounded_string; buf := get_line; a := integer'value(to_string(buf)); buf := get_line; put(a); put_line(buf);
Note that weird things can also occur when using consecutive get_line()
statements. For example consider the code:
s,t : string(1..4); get_line(s,len); put(s); put(len); get_line(t,len); put(t); put(len);
Here is an example of it running:
tool tool 4οΏ½# 0
The first string input βtoolβ. works, the second string reads in the line terminator. The same does not occur using the alternate form of get_line
. For example the code below works as it should.
s,t : string(1..4); s := get_line; put(s); t := get_line; put(t);