C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Of getline(cin,...), Ctrl+D and infinite loops

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Guest






PostPosted: Tue Apr 24, 2007 9:40 pm    Post subject: Of getline(cin,...), Ctrl+D and infinite loops Reply with quote



Here is a small program. It's meant to keep reading lines from the
stdin till someone types the (really cute) string "manchu". In that
case it breaks out of the loop and the program terminates.

///////////////////////////////////
#include <iostream>
#include <string>
using namespace std;

int main() {
string str;
char ch;
while ( cin ) {
cin.clear();
cin.ignore( cin.rdbuf()->in_avail() );
getline( cin, str, '\n');
if ( str == "manchu" )
break;
if ( cin.eof() || cin.fail() ) {
cin.clear();
}
}

return 0;
}


I am compiling this with gcc 3.3.1 on Solaris 9 SPARC, and with gcc
3.2.3 on RHEL 3.

Now here is the crux. I wanted that if the user just typed "Ctrl+D",
it should clear the eof and fail bits and continue the loop looking
for more input. It does this nicely on Linux but goes into an infinite
loop on Solaris sparc, repeatedly encountering EOF. I am guessing that
this is a wrong piece of code
and somehow it is working in one case, and not in the other case.

And hoping that someone actually points out where I am going wrong.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Sun Apr 29, 2007 5:46 pm    Post subject: Re: Of getline(cin,...), Ctrl+D and infinite loops Reply with quote



{ Please include attributions for quotes (whom is quoted), and please
don't /remove/ them. -mod/aps }

Quote:
And hoping that someone actually points out where I am going wrong.

The fact is that calling clear() only resets the status bits of the C++
stream object, but that may or may not affect the actual state of the
"controlled sequence", in this case the sequence of characters coming
from the console. What may be happening (and I stress *may* because we
are in realm of implementation-defined behaviour here) could be that by
pressing Ctrl+D the stdin stream is being closed. So even if call
clear() the stream will still remain closed (it's beyond the semantic of
clear() to reopen the stream): the next input operation will fail and
set again the eof+fail condition.


Indeed, that is all cin.clear() is guaranteed to do. I had to provide
some form of a fix for this (the code I posted was just a small stub
capturing the essence of the actual code in my app). I saw that a call
to:

::clearerr(stdin);

following the cin.clear() call allows inputs to happen again. This is
far from an ideal situation - I would really want my program to choke
on EOF rather than ignore it and treat it as null input. But "the
powers that be" reckoned that ignoring EOF is better. It certainly was
less effort for me.

I am actually surprised that my earlier program was taking inputs on
Linux and AIX after cin.clear(). After running the following program
on Solaris, AIX, Linux and FreeBSD, with identical output everywhere,
I would have guessed that my original program should have choked on
Ctrl+D everywhere - because cin.clear() never resets the state of the
C stream stdin.:


#include <iostream>
#include <string>
#include <cstdio>
using namespace std;

int main()
{
string str;
getline( cin, str );

if ( !cin ) {
if ( feof(stdin) )
cout << "1. feof(stdin)" << endl;
if ( ferror(stdin) )
cout << "1. ferror(stdin)" << endl;
}
cin.clear();
{
if ( feof(stdin) )
cout << "2. feof(stdin)" << endl;
if ( ferror(stdin) )
cout << "2. ferror(stdin)" << endl;
}
clearerr(stdin);
{
if ( feof(stdin) )
cout << "3. feof(stdin)" << endl;
if ( ferror(stdin) )
cout << "3. ferror(stdin)" << endl;
}

return 0;
}


Now does that mean that the iostream implementations in some places
have nothing to do with the stdio streams and in other places it does?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Mon Apr 30, 2007 5:55 pm    Post subject: Re: Of getline(cin,...), Ctrl+D and infinite loops Reply with quote



arindam.mukerjee (AT) gmail (DOT) com ha scritto:
Quote:

Now does that mean that the iostream implementations in some places
have nothing to do with the stdio streams and in other places it does?


The standard says in 27.3.1/1: "The object cin controls input from a
stream buffer associated with the object stdin, declared in <cstdio>."
Similary for cout and cerr in subsequent paragraphs. So definitely there
shall be a relationship between cin/cout/cerr and their stdio counterparts.

Notice, however, that it does *not* say "The object cin controls input
from stdin". The precise choice of words allows (intentionally, I
presume) different implementation strategies. For example, cin might
hold a copy of stdin and achieve control of the "stream buffer" through
it, or both cin and stdin might control a shared "stream buffer" object.

Besides these arguments, as the standard does not specify a behaviour in
the situation you are describing, the "unspecified" behaviour definition
applies: the behaviour "depends on the implementation. The
implementation is not required to document which behavior occurs." (1.3.13).

HTH,

Ganesh

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Tue May 01, 2007 7:38 pm    Post subject: Re: Of getline(cin,...), Ctrl+D and infinite loops Reply with quote

On Apr 25, 4:50 am, Ulrich Eckhardt <eckha...@satorlaser.com> wrote:
Quote:
arindam.muker...@gmail.com wrote:
int main() {
string str;
char ch;
while ( cin ) {
cin.clear();
cin.ignore( cin.rdbuf()->in_avail() );

Please read up what in_avail() returns, there are basically three distinct
value categories:
1. Nothing.
2. Something.
3. Unknown.
You don't handle the third case here in any meaningful way!


What are these three cases?
Nothing - there are no leftover chars in the buffer.
Something - there are.
Unknown - Is this the case when gptr is NULL and showmanyc is called
on the streambuffer?

I am not so great at iostreams anyway [and I wish that the Langer/
Kreft book becomes available in my country pretty soon] - so I am
getting all kinds of responses to my use of:

cin.ignore( cin.rdbuf()->in_avail() );

Is this a generally bad strategy to follow? I am using it in a
terminal based app in a scenario where between successive user inputs,
there would be prompts coming about to indicate when the user needs to
make an input next. Is this a flawed approach.

- Arindam


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ulrich Eckhardt
Guest





PostPosted: Wed May 02, 2007 6:08 pm    Post subject: Re: Of getline(cin,...), Ctrl+D and infinite loops Reply with quote

arindam.mukerjee (AT) gmail (DOT) com wrote:
Quote:
On Apr 25, 4:50 am, Ulrich Eckhardt <eckha...@satorlaser.com> wrote:
arindam.muker...@gmail.com wrote:
int main() {
string str;
char ch;
while ( cin ) {
cin.clear();
cin.ignore( cin.rdbuf()->in_avail() );

Please read up what in_avail() returns, there are basically three
distinct value categories:
1. Nothing.
2. Something.
3. Unknown.
You don't handle the third case here in any meaningful way!


What are these three cases?
Nothing - there are no leftover chars in the buffer.
Something - there are.
Unknown - Is this the case when gptr is NULL and showmanyc is called
on the streambuffer?

The last case is when the implementation does not determine the number of
available characters. The reasons for that could be that it either doesn't
care, i.e. the programmer was simply too lazy to do it or that it is simply
impossible to implement. In particular for stdin or similar non-file
streams it is impossible to tell how many characters can be read, the best
one could do is to return how many were buffered in advance. Since this is
by no means a guarantee for anything, I as a programmer of the streambuffer
also just wouldn't bother.


Quote:
I am not so great at iostreams anyway [and I wish that the Langer/
Kreft book becomes available in my country pretty soon] - so I am
getting all kinds of responses to my use of:

cin.ignore( cin.rdbuf()->in_avail() );

Is this a generally bad strategy to follow? I am using it in a
terminal based app in a scenario where between successive user inputs,
there would be prompts coming about to indicate when the user needs to
make an input next. Is this a flawed approach.

There are two approaches I usually take:
1. input, compute, output
You read from stdin, compute whatever you need and output the results to
stdout. This is the typical behaviour for Unix apps like grep and sed. If
you encounter an error or EOF, you terminate.
2. interactive
This intersperses output to a user and input, often looping. Here, I usually
use getline() to gather input and then use stringstreams to parse it.

You mentioned in another reply in this thread that "the powers that be" want
it to ignore EOF. What are the precise reasons? My point is that for case 1
above, terminating on EOF is mandatory while for case 2, a user pressing
control-D is also explicitly requesting a shutdown so there is also no
point in ignoring this request. In either case, trying to ignore EOF would
be a flawed approach, hence I ask what the rationale was for that decision.

Uli

--
Sator Laser GmbH
Geschäftsführer: Ronald Boers, Amtsgericht Hamburg HR B62 932


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
 


Powered by phpBB © 2001, 2006 phpBB Group