I'm starting with C++ in college (before used Modula2). I have problems with cin.
While interacting with the user, I need to recognize certain "commands".,
For example "addClient Rafael". I handle it the following way
cin >> command, strcoll (command, "addClient"), and then, if command equals addClient, y do
cin >> command2 (so I read Rafael),. and do the proper procedures...
But also, I have to recognize "deleteAll" which deletes all my database, so I dont have to read the second parameter.
When someone enters random things such as "skjdsjfnsdj" its supossed to say "Wrong command" for which, if command didnt equal none of my "known" commands it printf "wrong command".
The problem is, when some types "skajskajs jakasjkajs" it says "wrong command. worng command"... it should only say it once...
So, "noskip" i thing is no use, maybe if i could break the string.., maybe a simpler way, help anyone?
The most flexible and intuitive way to do this is as follows:
bool done = false;
while( !done ) {
string commandLine, cmd, value;
getline( cin, commandLine );
istringstream ss(commandLine);
ss >> cmd >> value;
if( cmd == "deleteAll" ) {
// BOOM
}
else if( cmd == "addClient" ) {
// Do something with 'value'. You could wait until here to read it
// if you want, instead of always attempting to read it.
}
else if( cmd == "quit" ) {
done = true;
}
else {
cout << "Wrong command\n";
}
}
Or edit to suit your purposes. I use this sort of approach for parsing simple key/value pair config files. Works a treat, and takes almost no effort to code.
You could simply try istream::getline() instead.
It will prevent the message appearing more than once for each command (separated by a \n).
Related
There are some variations of this question but none exactly matches what I'm looking for.
Giving the following code:
string command="";
while (command.compare("quit")!=0)
{
os << prompt;
getline(is,command);
}
How may I detect if getline reached eof (end of file)
getline returns a reference to the stream you pass to it, and that stream will evaluate to false if it hits a failure state. Knowing that, you can leverage that to move getline into the condition for the while loop so that if it fails, then the condition will be false and the loop stops. You can combine that will your check for quit as well like
while (getline(is,command) && command != "quit")
{
// stuff
}
You can also add the prompt to the loop like
while (os << prompt && getline(is,command) && command != "quit")
while (command.compare("quit")!=0)
{
os << prompt;
getline(is,command);
if (is.eof())
do something at end of file
}
But note that is reaching end of file does not mean that there isn't something in command. You can read data and reach the end of file at the same time.
What you might be looking for instead is this
os << prompt;
while (getline(is,command) && command != "quit")
{
do something with command
os << prompt;
}
That code will quit the loop if you reach end of file and nothing has been input, or if 'quit' is input.
I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.
So I've run into the following problem. My goal is to create a loop that keeps taking user input over and over until the user doesn't enter anything into 'cin >>', leaves the line blank, and simply presses the ENTER key to move on, at which point the program is supposed to break out of the loop and continue on with the rest of program execution. Something like this:
do {
cout << "\nEnter a name: ";
cin >> input1;
if (input1.empty())
{
break;
}
else
{
user_name = input1;
}
} while (!input1.empty());
As you can see, I've already tried using the empty() function, but that didn't work, the program simply stays in the loop and doesn't break out, no matter how many times I press enter. It just keeps prompting me to enter a name. I've also tried using something like
if (input1 == "")
but that doesnt work either. Can anyone help? How do I break out of this loop?
UPDATE: OK guys, I've tried your recommendations, and it worked! Thank you so much! Unfortunately, although the getline function works, it has also created a new problem for me. Basically, in the first initial loop, the program prompts for a name, I type in a name, and the name is stored in user_name. However, in the SECOND loop, the program doesn't even give me the chance to enter any input, it simply prints "Enter a name: ", and then instantly exits out of the loop, and continues on with the rest of program execution. Why is this happening?
Use this getline(std::cin, input1):
while (getline(std::cin, input1))
{
if (input1.empty())
break;
username =input1;
std::cout << input1 << std::endl << "Enter Input : ";
}
Use std::getline(cin, input1); instead to read a line from the console.
Using cin directly reads exactly one word from stdin. If the user does not input anything, no word has been given and cin does not return yet (your empty check is not even executed).
After you use std::getline you can leave your empty-check as-is:
std::getline(cin, input1);
if(input1.empty())
break;
BTW: In C++ you should also check if the underlying stream has run into an error. So check the return code of cin or getline. This can be done with the following code:
if(!std::getline(cin, input1))
// I/O error
In general, looping until an empty line is entered would be:
while ( std::getline( line ) && !line.empty() ) ...
If you need a prompt: the prompt is part of the input logic, and
should be implemented as such:
std::string
getlineWithPrompt( std::string const& prompt )
{
std::cout << prompt;
std::string results;
return std::getline( std::cin, results )
? results
: std::string();
}
You then do something like:
std::string line = getlineWithPrompt( "prompt for first line" );
while ( !line.empty() ) {
// ...
getlineWithPrompt( "prompt for further line" );
}
(This is actually somewhat simplified, as it treats hard errors
on input, end of file, and empty lines identical, which is
rarely the right thing in professional software. But for
learning purposes, it should be sufficient.)
Cin won't read the whitespace that you call an empty line. Getline may do this, but I am not entirely sure. You could define an end character that the user would type and check for that. Gets would also work, it will just set the starting character to 0x0. Be careful with gets(), it is prone to allow buffer overflows.
This works as well:
char line[128];
do
{
cout << "Enter something: ";
gets(line);
} while (strcmp(&line[0], "\0") != 0);
#JamesKanze
So something like this to exit the while loop?
string str = "foo";
while (str == "foo"){
getline(cin, str);
}
str = "foo";
In the C++ Without Fear: A Beginner's Guide That Makes You Feel Smart book in chapter(8), part of a code trying to display a text file is the following:
while(1)
{
for(int i=1; i <= 24 && !file_in.eof(); i++)
{
file_in.getline(input_line,80);
std::cout<<input_line<<std::endl;
}
if(file_in.eof())
{
break;
}
std::cout<<"More? (Press 'Q' and ENTER to quit.)";
std::cin.getline(input_line,80);
c=input_line[0]; // <<<<<<
if(c=='Q'||c=='q')
{
break;
}
}
The part I'm not getting here is:
c=input_line[0];
I think it is put to read 'Q' or 'q'. But, why using this form (Array)? And, isn't there a way to read 'Q' or 'q' directly?
I tried std::cin>>c; but seemed to be incorrect.
Any ideas?
Thanks.
Because input_line is string ( array from chars), so input_line[0] gets the first letter - this is in case, that the user write "quit" or "Quit", not just "Q"
std::cin >> c; would be correct, if you enter just one char and press Enter
I tried std::cin>>c; but seemed to be incorrect.
That's correct, if c is a char.
You're right; reading an entire line just to extract a single character is bizarre. I recommend a book from this list.
You are getting the first character from the "array" into which the input line has been written.
NON-STANDARD solution, but works on windows platforms.
you can use getch() function defined in conio.h
example:
#include <conio.h>
...
char c = getch();
bye
I'm a bit confused by the results of the following function:
int main() {
string command;
while(1) {
cin >> command;
if(command == "end")
return 0;
else
cout << "Could you repeat the command?" << endl;
}
return 0;
}
First of all - the output line ("could you...") repeats once for each individual word in the input (stored in command). So far as I can see, it should only be possible for it to happen once for each instance of the loop.
Also, when the line 'if(command == "end")' is changed to 'if(command == "that's all")' it never triggers. A little testing suggested that all of the whitespace was removed from the command.
Could someone explain to me what's going on here?
Thanks
The formatted input operator >>() reads space separated tokens from input. If you want to read whole lines, use the getline() function:
string command;
getline( cin, command );
Most (possibly all) operating systems buffer input. When you type a string of words and then hit [enter] it is only at the time you hit enter that the input is usually passed to your program. Thus that is when it will start reading the input and separating it out into individual words (because as Neil mentions, the >> reads words, not lines). Thus your program goes through the loop multiple times (once per word you had in the line) even though you only hit enter once.
So, you are correct when you think it should only display "could you..." once per loop. That is what is happening.
Likewise, you'll never have a command that contains more than one word because of the space delimiter. As mentioned, use getline() to retrieve the entire text for the line you entered.