Recent

Author Topic: Why readln behaves differently with two string variables  (Read 933 times)

Yiyuan

  • New member
  • *
  • Posts: 9
Why readln behaves differently with two string variables
« on: July 25, 2020, 10:39:50 am »
Hi friends, I have some confusions about how the ‘readln“ works.
This is an example:
Code: Pascal  [Select][+][-]
  1. program test;
  2. var
  3.    first: string;
  4.    second: string;
  5. begin
  6.    writeln('Please enter your first and second name:');
  7.    readln(first, second);
  8.    writeln('your first name is ', first, ' second name is ', second);
  9.    readln;
  10. end.
  11.  
when I inputted some string and entered 'return', the console would directly print the result though 'second' had not been assigned  a value. 'second' just used the default value ''.
But if I change the program to this:
Code: Pascal  [Select][+][-]
  1. program test2;
  2. var
  3.    first: string;
  4.    age: integer;
  5. begin
  6.    writeln('Please enter your first name and age:');
  7.    readln(first, age);
  8.    writeln('your first name is ', first, ' and age is ', age);
  9.    readln;
  10. end.
  11.  
After I inputted some string and entered 'return', the console would wait for my next input for 'age' variable and then printed the correct result.
I wonder why the readln behaves differently when it receives two string variables. Also, I wonder where I can find the details of readln's implementation.  I didn't find it in the FPC source directory.
« Last Edit: July 25, 2020, 10:42:34 am by Yiyuan »

julkas

  • Hero Member
  • *****
  • Posts: 630
  • KISS principle / Lazarus 2.0.6 / FPC 3.0.4
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

Yiyuan

  • New member
  • *
  • Posts: 9
Re: Why readln behaves differently with two string variables
« Reply #2 on: July 25, 2020, 12:54:42 pm »
Thanks. But this link still doesn't solve my problem. I know all white spaces and number will be as part of a string. But why does the console not wait for a next input when the second variable is a string instead of a integer after I terminate the first input with a return.

lucamar

  • Hero Member
  • *****
  • Posts: 2975
Re: Why readln behaves differently with two string variables
« Reply #3 on: July 25, 2020, 02:00:02 pm »
I couldn't follow too deeply, since Read(Ln) and Write(Ln) are somewhat "special" and it's not very easy to follow  the convolutions they go through, but it seems that when trying to read the second string ReadLn() finds the previously read EOL and assumes the string is empty (as if the user had pressed just <Enter>), while in the second case it diverts to number-reading after clearing the buffer.

The upshot is that to read more than one string it's better to read each in it's own call to ReadLn(), maybe prefixed by the field identifier:

Code: Pascal  [Select][+][-]
  1. var
  2.   First, Second: string;
  3.  
  4. begin
  5.   Write('Who''s on First? '); ReadLn(First);
  6.   Write('Which''s on Second? '); ReadLn(Second);
  7.   WriteLn('First is "', First, '" and Second is "', Second, '"');
  8. end.

Now the question becomes whether this is a bug or "as intended". :-\
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Yiyuan

  • New member
  • *
  • Posts: 9
Re: Why readln behaves differently with two string variables
« Reply #4 on: July 25, 2020, 02:50:50 pm »
but it seems that when trying to read the second string ReadLn() finds the previously read EOL and assumes the string is empty (as if the user had pressed just <Enter>), while in the second case it diverts to number-reading after clearing the buffer.
Thank you for your kind reply. Your answer inspired me to try again. In two string variables example, I just inputted a space for 'first' and entered 'return', the program did not think it a qualified value and continued waiting for input and if I just entered 'return', the program would not end.

lucamar

  • Hero Member
  • *****
  • Posts: 2975
Re: Why readln behaves differently with two string variables
« Reply #5 on: July 25, 2020, 03:44:16 pm »
Hmmm .... It doesn't happen here (Xubuntu 18.04, amd64). I used this simple program to test your initial and the new post:
Code: Pascal  [Select][+][-]
  1. program ReadLnTest;
  2.  
  3. var
  4.   First, Second: string;
  5.   Number: Integer;
  6.  
  7. begin
  8.   First := 'First';
  9.   Second := 'Second';
  10.   Number := 0;
  11.  
  12.   WriteLn('reading two strings: ');
  13.   ReadLn(First, Second);
  14.   WriteLn('First became "', First, '" and Second is now "', Second, '"');
  15.  
  16.   Writeln('Let''s try now with string, integer:');
  17.   ReadLn(First, Number);
  18.   WriteLn('First is "', First, '" and Number is ', Number);
  19.  
  20.   Writeln('Testing now individual ReadLn''s:');
  21.   Write('First? '); ReadLn(First);
  22.   Write('Second? '); ReadLn(Second);
  23.   WriteLn('First is "', First, '" and Second is "', Second, '"');
  24. end.

The interesting part, about your last post, is the last one; responding with <Enter> for First and with a space for Second results in this:

Code: [Select]
Testing now individual ReadLn's:
First?
Second? 
First is "" and Second is " "

as expected. Note that AFAICR it has always worked thus, even with Borland's Turbo Pascal.

Can you show the code you're using?
« Last Edit: July 25, 2020, 03:47:42 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Yiyuan

  • New member
  • *
  • Posts: 9
Re: Why readln behaves differently with two string variables
« Reply #6 on: July 25, 2020, 04:12:40 pm »
Sorry, my last post is wrong. I can not figure out the reasons. Maybe it was just a mistake. My laptop is windows10, amd64, Lazarus 2.0.10.
The code for my last post is:
Code: Pascal  [Select][+][-]
  1. program test;
  2. var
  3.    first: string;
  4.    second: string;
  5. begin
  6.   writeln('Please enter two names: ');
  7.   readln(first, second);
  8.   writeln('your first name is "', first, '" your second name is "', second,'"');
  9.   readln;
  10. end.
  11.  
If I responsed the first with enter, the result would be directly displayed
Code: Bash  [Select][+][-]
  1. Please enter two names:
  2.  
  3. your first name is "" your second name is ""
  4.  
The problem with first post still exists.
« Last Edit: July 25, 2020, 05:06:04 pm by Yiyuan »

themagicm

  • New member
  • *
  • Posts: 5
Re: Why readln behaves differently with two string variables
« Reply #7 on: July 28, 2020, 03:48:40 am »
You need to use a delimiter if you're going to use String, I believe.

If you set the vars to int and type 1 2 you'll get the values assigned to the correct variable.  I changed your code to use int instead of string and it worked correctly.

lucamar

  • Hero Member
  • *****
  • Posts: 2975
Re: Why readln behaves differently with two string variables
« Reply #8 on: July 28, 2020, 08:10:43 am »
You need to use a delimiter if you're going to use String, I believe.

Nope. Whatever you type, up to the EOL, is returned into the first string and the second returns empty. I'm not entirely sure but, as stated above, I think the problem is that ReadLn() doesn't consume the EOL so it finds it again when trying to read the second string and assumes it's an "empty" response from the user.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

themagicm

  • New member
  • *
  • Posts: 5
Re: Why readln behaves differently with two string variables
« Reply #9 on: July 28, 2020, 04:11:16 pm »
I dunno.  But once it hits the EOL, it doesnt ask for the second variable.  If it was me, I wouldnt spend days on why a second variable isnt read and do what works.

winni

  • Hero Member
  • *****
  • Posts: 1616
Re: Why readln behaves differently with two string variables
« Reply #10 on: July 28, 2020, 05:50:07 pm »
whatever you type, up to the EOL, is returned into the first string and the second returns empty. I'm not entirely sure but, as stated above, I think the problem is that ReadLn() doesn't consume the EOL so it finds it again when trying to read the second string and assumes it's an "empty" response from the user.

Hi!

Readln consumes the LineEnding and sets EOL to true. Job is done.
As it is implemented in fpc you cannot read 2 (ore more) strings with one readln.

AFAIR this was implemented different in UCSD:
A #32 was a separator between two variables - no matter if Integer , Float or string.

Winni

Yiyuan

  • New member
  • *
  • Posts: 9
Re: Why readln behaves differently with two string variables
« Reply #11 on: July 31, 2020, 07:18:35 am »
Thanks for all of you. I think I have got so much useful knowledge when exploring this question. As a student, it's worth it.
« Last Edit: July 31, 2020, 07:26:47 am by Yiyuan »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8616
  • FPC developer.
Re: Why readln behaves differently with two string variables
« Reply #12 on: July 31, 2020, 09:24:43 am »
Basically

Code: Pascal  [Select][+][-]
  1. readln(a,b,c,d);

means

Code: Pascal  [Select][+][-]
  1. read(a); read(b); read(c) readln(d);

However while reading e.g. integers are clearly delimited (anything numeric, and some ['-','.','E'] handling till a space or lf), strings always read till eol.

So basically a readln(s,s2);  read(s) till end of the line, and then the readln(s2) reads the eol itself.

ASBzone

  • Sr. Member
  • ****
  • Posts: 452
  • Automation leads to relaxation...
    • Free BrainWaveCC Console Utilities
Re: Why readln behaves differently with two string variables
« Reply #13 on: July 31, 2020, 07:59:37 pm »
Basically

Code: Pascal  [Select][+][-]
  1. readln(a,b,c,d);

means

Code: Pascal  [Select][+][-]
  1. read(a); read(b); read(c) readln(d);

However while reading e.g. integers are clearly delimited (anything numeric, and some ['-','.','E'] handling till a space or lf), strings always read till eol.

So basically a readln(s,s2);  read(s) till end of the line, and then the readln(s2) reads the eol itself.

I guess that makes sense, relative to how:

Code: Pascal  [Select][+][-]
  1. writeln(a, b, c d);
  2.  

is equivalent to:

Code: Pascal  [Select][+][-]
  1. write(a); write(b); write(c); writeln(d);
  2.  

Perhaps it is time for a ReadEachLn command!   LOL
-ASB: https://www.BrainWaveCC.com

Lazarus v2.0.11 r63516 / FPC v3.2.1-r45705 (via FpcUpDeluxe) -- Windows 64-bit install w/32-bit cross-compile
Primary System: Windows 10 Pro x64, Version 2004 (Build 19041.388)
Other Systems: Windows 10 Pro x64, Version 2004 or greater

lucamar

  • Hero Member
  • *****
  • Posts: 2975
Re: Why readln behaves differently with two string variables
« Reply #14 on: July 31, 2020, 08:53:44 pm »
So basically a readln(s,s2);  read(s) till end of the line, and then the readln(s2) reads the eol itself.

Yeah, that's what I meant with my (certainly unclear) "doesn't consume the eol". I guess it's not that easy to implement, because the special status or read(ln)/write(ln) but maybe with consecutive strings it should behave as if you had written:
Code: Pascal  [Select][+][-]
  1. readln(first); readln(second)

Or perhaps what it really merits is a mention or a more thorough explanation (say, Marco's one, above) in the documentation? Just an idea ... :-\
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

 

TinyPortal © 2005-2018