cin, iostream problems

C

Christopher

I am trying to get a line from the user which could be anything, I am
expecting either a string followed by a whitespace or just a string by
itself. I have tryed using string::getline, stringstreams, and all
sorts of cin variations and can't get it right. Currently my program
stops, waiting for more input in the case the user just enters a
command with no argument, in this block of code. How can I fix it up?

void Menu()
{
string command;
int argument;

string::size_type index = string::npos;

while(command != "quit")
{
cout<<"\nThe Following are valid commands:\n";
cout<<"read_all <number> -- display entire mail header and body.\n";
cout<<"read <number> -- display body of message\n";
cout<<"del <number> -- delete message\n";
cout<<"undel -- undo all deletion\n";
cout<<"reply <number> -- reply to message\n";
cout<<"list <number> -- display the next 10 message
summaries\n";
cout<<"quit -- exit this program\n\n";

cin>>command;

if(!(cin>>argument))
argument = 0;

cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

if(command == "read_all")
cout<<"not implemented\n";

else if(command == "read")
cout<<"not implemented\n";

else if(command == "del")
cout<<"not implemented\n";

else if(command == "undel")
cout<<"not implemented\n";

else if(command == "reply")
cout<<"not implemented\n";

else if(command == "list")
cout<<"not implemented\n";
}
}

Thanks,
Christopher
 
L

Leor Zolman

I am trying to get a line from the user which could be anything, I am
expecting either a string followed by a whitespace or just a string by
itself. I have tryed using string::getline, stringstreams, and all
sorts of cin variations and can't get it right. Currently my program
stops, waiting for more input in the case the user just enters a
command with no argument, in this block of code. How can I fix it up?

It is stopping and waiting for an argument after any initial command, even
the ones that don't take an argument. This can be remedied easily enough by
simply modifying your logic to treat commands with args differently from
those without args. Here's a step in the right direction (but there are
still flaws, which I'll mention afterwards):

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

void Menu()
{
string command;
int argument;

// string::size_type index = string::npos;

while(command != "quit")
{
cout<<"\nThe Following are valid commands:\n";
cout<<"read_all <number> -- display entire mail header and
body.\n";
cout<<"read <number> -- display body of message\n";
cout<<"del <number> -- delete message\n";
cout<<"undel -- undo all deletion\n";
cout<<"reply <number> -- reply to message\n";
cout<<"list <number> -- display the next 10 message
summaries\n";
cout<<"quit -- exit this program\n\n";

cin>>command;

if(command == "undel")
cout<<"not implemented\n";
else if(command == "quit")
return;
else
{
if(!(cin>>argument))
argument = 0;

cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

if(command == "read_all")
cout<<"not implemented\n";

else if(command == "read")
cout<<"not implemented\n";

else if(command == "del")
cout<<"not implemented\n";

else if(command == "reply")
cout<<"not implemented\n";

else if(command == "list")
cout<<"not implemented\n";

else
cout << "Invalid command!\n";

}
}
}


int main()
{
Menu();
return 0;
}


The problem now is that if the user enters an invalid command, it'll still
wait for that arg before diagnosing it. If it were me, I'd manually deal
with the arg for each case that requires it. You'll have more lines of
code, but at least it'll be straight-forward. Alternatively, you can
process just the command name by calling a function that matches it to a
valid string (perhaps returning an enum representing the command), and that
also categorizes the command as taking or not taking an arg (perhaps via a
bool reference argument the function sets). Then you'd just check that
bool's value after the call to find out whether or not to attempt to
consume an argument.
-leor
 
C

Christopher

Leor Zolman said:
It is stopping and waiting for an argument after any initial command, even
the ones that don't take an argument. This can be remedied easily enough by
simply modifying your logic to treat commands with args differently from
those without args. Here's a step in the right direction (but there are
still flaws, which I'll mention afterwards):

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

void Menu()
{
string command;
int argument;

// string::size_type index = string::npos;

while(command != "quit")
{
cout<<"\nThe Following are valid commands:\n";
cout<<"read_all <number> -- display entire mail header and
body.\n";
cout<<"read <number> -- display body of message\n";
cout<<"del <number> -- delete message\n";
cout<<"undel -- undo all deletion\n";
cout<<"reply <number> -- reply to message\n";
cout<<"list <number> -- display the next 10 message
summaries\n";
cout<<"quit -- exit this program\n\n";

cin>>command;

if(command == "undel")
cout<<"not implemented\n";
else if(command == "quit")
return;
else
{
if(!(cin>>argument))
argument = 0;

cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

if(command == "read_all")
cout<<"not implemented\n";

else if(command == "read")
cout<<"not implemented\n";

else if(command == "del")
cout<<"not implemented\n";

else if(command == "reply")
cout<<"not implemented\n";

else if(command == "list")
cout<<"not implemented\n";

else
cout << "Invalid command!\n";

}
}
}


int main()
{
Menu();
return 0;
}


The problem now is that if the user enters an invalid command, it'll still
wait for that arg before diagnosing it.

Yea I tryed that way and that's why I tossed it out
..
If it were me, I'd manually deal
with the arg for each case that requires it. You'll have more lines of
code, but at least it'll be straight-forward.

I'd love to and that's the way I would normally do it, but the instructor
won't accept that. He wants us to parse a line of input like it was 1970.
I'd use a char array and do it the old fashion way but I hate c style
strings and would much rather find out if there is a way to tell if
something
is sitting in the cin stream then stick it into the argument variable if it
exists in a c++ fashion.
Alternatively, you can
process just the command name by calling a function that matches it to a
valid string (perhaps returning an enum representing the command), and that
also categorizes the command as taking or not taking an arg (perhaps via a
bool reference argument the function sets). Then you'd just check that
bool's value after the call to find out whether or not to attempt to
consume an argument.
-leor

It would still hang if the user was dumb and didn't enter an argument. I am
aiming for getting the whole line
and then seeing if an argument exists when it should and if it isn't or it
isn't a number then giving an error message.

Appreciate the input though,
Chris
 
L

Leor Zolman

I'd love to and that's the way I would normally do it, but the instructor
won't accept that. He wants us to parse a line of input like it was 1970.
I'd use a char array and do it the old fashion way but I hate c style
strings and would much rather find out if there is a way to tell if
something
is sitting in the cin stream then stick it into the argument variable if it
exists in a c++ fashion.

If you want to do it like "1970", (well, 1980 more likely, at least if
you're not Dennis Ritchie...) then "think fgets and sscanf", but do it with
iostreams! Just read the entire line into a std::string using getline, and
start analyzing after it has been input. You can use <sstream> facilities
to create an istringstream from the input string, then just extract from
that and test the stream state after each extraction.
Good luck,
-leor
 
C

Christopher

Leor Zolman said:
If you want to do it like "1970", (well, 1980 more likely, at least if
you're not Dennis Ritchie...) then "think fgets and sscanf", but do it with
iostreams! Just read the entire line into a std::string using getline, and
start analyzing after it has been input. You can use <sstream> facilities
to create an istringstream from the input string, then just extract from
that and test the stream state after each extraction.
Good luck,
-leor


--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html

Well here is my attempt. I don't understand why if I put cin.clear();
cin.ignore(std::numeric_limits::max(),'\n'); after the input that i have to
hit enter twice.
I thought I had to put that after using the instream to make sure there
wasn't any garbage left for the next function who wants to use it. So I took
it out.
Here is my code, please make any suggestions that would make it better and
more standard like:
void Menu()
{
string command;
int argument;
while(true)
{
cout<<"\nThe Following are valid commands:\n";
cout<<"read_all <number> -- display entire mail header and body.\n";
cout<<"read <number> -- display body of message\n";
cout<<"del <number> -- delete message\n";
cout<<"undel -- undo all deletion\n";
cout<<"reply <number> -- reply to message\n";
cout<<"list <number> -- display the next 10 message summaries\n";
cout<<"quit -- exit this program\n\n";
getline(cin, command, '\n');
// Extract command and argument
stringstream temp(command);
temp>>command;
if(!(temp>>argument))
argument = 0;
// Check for valid commands and perform them
if(command == "read_all" && argument)
cout<<"not implemented\n";
else if(command == "read" && argument)
cout<<"not implemented\n";
else if(command == "del" && argument)
cout<<"not implemented\n";
else if(command == "undel")
cout<<"not implemented\n";
else if(command == "reply" && argument)
cout<<"not implemented\n";
else if(command == "list" && argument)
cout<<"not implemented\n";
else if(command == "quit")
break;
else
cout<<"\nInvalid command or argument\n";
}
}

sorry my email client hates tabs for some reason, but I think it's still
readable.
Thanks,.
Chris
 
L

Leor Zolman

Well here is my attempt. I don't understand why if I put cin.clear();
cin.ignore(std::numeric_limits::max(),'\n'); after the input that i have to
hit enter twice.
I thought I had to put that after using the instream to make sure there
wasn't any garbage left for the next function who wants to use it. So I took
it out.

Why bother clearing the input? You've read in an entire line, you're
processing it, and the next time 'round you're getting an entirely new
line...so it doesn't really matter if there are items remaining on the
previous line or not. If you weren't reading an entire line at a time, but
extracting directly from cin instead of from the stringstream , then you'd
need to worry about extraneous characters. In that case, I've seen various
posts showing elaborate ways of doing it, but so far I've done OK just
reading characters until I encounter a newline. YMMV.

(And by the way, istringstream seems as if might be a better fit to your
context than stringstream, since you're just using it for input.)

Other than that, what you have looks OK to me. When you post in the future,
though, please consider posting a complete program, with headers and a
driver, as I did in my post. It's just a way of being considerate to folks
who're inclined to fire up your code; in fact, it would be likely to make
them more inclined.

And newsreaders are weird about tabs. When I copied and pasted your code,
it came up in my editor with all the tabs intact and looking mighty purdy.
What I do personally when posting code, though, is use an Epsilon keystroke
macro I wrote to "untabify" code, put the result into the clipboard, and
then re-tabify it in my editor's buffer. Then I just paste the untabified
code into the body of my post. Now all I have to do is to remember to hit
that magic key instead of doing the usual mark-and-copy dance. I've been
doing well, since the keystroke macro is easier than the dance ;-)
-leor
 
L

Leor Zolman

And newsreaders are weird about tabs. When I copied and pasted your code,
it came up in my editor with all the tabs intact and looking mighty purdy.

Well, I just figured out why /that/ happened. As I mentioned, I use
Epsilon; it auto-formatted the code for me because it knew I was editing a
C++ document. I just didn't realize it did that upon text pasted in from
the clipboard... I do like Epsilon a lot ;-)
-leor
 
J

John Harrison

Well here is my attempt. I don't understand why if I put cin.clear();
cin.ignore(std::numeric_limits::max(),'\n'); after the input that i have to
hit enter twice.

Because cin.ignore(std::numeric_limits::max(),'\n'); means ignore input upto
the next newline. If there is no newline pending then you are going to have
to input another.

john
 
S

Siemel Naran

Christopher said:
cout<<"\nThe Following are valid commands:\n";
cout<<"read_all <number> -- display entire mail header and body.\n";
cout<<"read <number> -- display body of message\n";
cout<<"del <number> -- delete message\n";
cout<<"undel -- undo all deletion\n";
cout<<"reply <number> -- reply to message\n";
cout<<"list <number> -- display the next 10 message
summaries\n";
cout<<"quit -- exit this program\n\n";

cin>>command;
if(!(cin>>argument))

One solution is to use cin.getline to read into a string one line terminated
by a newline character. Then use istringstream to parse the command and
command line arguments.

std::string linestring;
getline(std::cin, linestring);
std::istringstream line(linestring);
line >> command >> argument;
 
D

Dave Moore

Siemel Naran said:
One solution is to use cin.getline to read into a string one line terminated
by a newline character. Then use istringstream to parse the command and
command line arguments.

std::string linestring;
getline(std::cin, linestring);
std::istringstream line(linestring);
line >> command >> argument;

Even better, the OP can easily get the behavior he wants (i.e. reading
variable arguments) by checking the state of the istringstream between
the operator>> calls. However, I posted such a solution the last time
he asked this question,

http://groups.google.com/[email protected]

so I guess that is not what he wants.

Dave Moore
 
C

Christopher

Dave Moore said:
"Siemel Naran" <[email protected]> wrote in message

Even better, the OP can easily get the behavior he wants (i.e. reading
variable arguments) by checking the state of the istringstream between
the operator>> calls. However, I posted such a solution the last time
he asked this question,

http://groups.google.com/[email protected]

so I guess that is not what he wants.

Dave Moore

It really was and that's what I ended up doing. Problem was when I tryed it
the first time, evidently there was a problem with the way I was testing the
output and it made it appear as if it wasn't working. It wasn't until I
tryed it every other way possible that I came back around and did it again
to find that it did indeed work the way I wanted. Lesson learned: don't
concentrate so much on the problem so much that you forget how your testing
the solution.
Thanks,
Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,150
Latest member
MakersCBDReviews
Top