Goal
New to c++ and haven't found a definitive answer on this question anywhere else. I'm working on a simple program that reads in a message typed in from the user on from within the console. It's an exercise for using string variables/concatenation.
I need to create loop that reads in the user input, which may contain multiple lines of input from the command shell.
So my function needs to read that input, while ignoring newlines, and end if a user inputs two "&&" on a new line.
Attempt
So here's my function:
string get_message() {
string message, line;
cout << "Enter the message > ";
cin.ignore(256, '\n');
while (getline(cin, line) && line != "&&") {
message = message + " " + line;
cout << message;
cin.clear();
}
return message;
}
The issue I'm running into is that within the while loop, until && is found, the loop content doesn't appear to run. Meaning when I cout << message I only get the single previous line of input.
Sample Run
Enter the Message > Messages.. this is a new message.
I'm a message on a new line, look at me.
New line.
&&
"New line." <--- from console cout
Result: New line.
Questions:
When does the loop content get called?
Why do I only get the previous line and not ALL previously (supposedly) concatenated lines?
Is there a better way to code this?
Breaking this down:
string get_message() {
string message, line;
cout << "Enter the message > ";
Standard stuff. Nothing to see here. Move along.
cin.ignore(256, '\n');
Discard the first line or 256 characters, whichever comes first. Probably not what you want to do. Ideologically, if you think there might be crap in already the stream, empty the stream before calling the function. Anyway, definitely part of OP's problem.
while (getline(cin, line) && line != "&&") {
While successfully got a line AND line is not "&&". Looks good. NOte: The new lines are stripped by the getline function because they're the token delimiter and leaving them in the returned token or leaving them in the stream would just cause problems.
message = message + " " + line;
Append line to message
cout << message;
Write message to output. There is no flushing going on, so when message makes it to the screen is unpredictable. This may be a cause of part of OP's problem.
cin.clear();
Clear error condition on cin. Not needed. If cin was in an error condition, the while loop would not have entered.
}
return message;
}
Normal stuff. Nothing to see here, but if the program ends shortly after this point, cout.flush() is called, std::flush is sent to cout, or there is a cout << endl;, cout will be flushed and the messages will suddenly appear.
So, using OP's input:
Messages.. this is a new message.
This is obliterated by cin.ignore
I'm a message on a new line, look at me.
Should appear eventually. No clue why OP doesn't see it. I'm unable to reproduce.
New line.
Should appear eventually.
&&
Ends input.
Output should be:
I'm a message on a new line, look at me. I'm a message on a new line, look at me. New line.
And I'm stumped as to why the OP doesn't get this the first time cout gets flushed. As I said, unable to reproduce.
Return should be:
I'm a message on a new line, look at me. New line.
Related
My code is rather simple. I have a method called promptUserInput that is defined in UtilityFunctions.h; it is implemented in UtilityFunctions.cpp.
My main method includes UtilityFunctions.h. I've correctly written my makefile, and it compiles without issue.
My main method's first line reads:
string input = promptUserInput();
And here's the actual implementation of the promptUserInput function:
/* Prompts user to enter expression */
string promptUserInput()
{
string userInput;
cout << "> ";
getline(cin, userInput);
return userInput;
}
But when the program runs, it doesn't display the > symbol. Instead, there's an empty line waiting for user input. I enter some arbitrary character, hit Enter, and the > symbol appears afterwards. None of this makes sense to me. What's going on?
std::cout uses buffered output, which should always be flushed. You can achieve this by using std::cout.flush() or std::cout << std::flush.
You can also use std::cout << std::endl, which writes a line break and then flushes, but the line break might not satisfy your intention.
I need to read lines from standard input, but I dont really know, how many it will be.
I tried to do it with getline() and cin combined with a while loop, but it led to an infinite loop:
string line;
while( getline(cin, string) ){...}
or
string word;
while( cin >> word ){...}
it doesnt stops at the end of the input( the lines are coming at one time, so the user is hitting just one time the Enter key ).
Thanks for your help.
Reading your comments you have a misunderstanding of "end of input".
When you start your program it waits for input from console, and if input is available it reads it. Initially your copy some strings to your console so your program takes this as input. But your program still keeps reading from the console because there was no "end of input". The program is still connected to the console.
You need to signal "end of input" to your program. On Windows you do this by pressing Ctrl+Z. On Linux you need to press Ctrl+D.
Your problem is reading from the console.
As your console does not put an EOF(end of file) when you enter an empty line.
You should try pipeing the input from a file to your program. This should end, when there is no more input.
Otherwise, just check if the string is empty, and break out of the loop, if it is empty.
The way you run your program, your input doesn't end, since the console can always provide more input. Your program behaves correctly, though perhaps not in the way you desire. That's because you have misunderstood your own desires.
What you are looking for is perhaps (but I can't be sure) for the program to end when either the input ends or when the input contains a blank line. This can be coded as follows:
int main()
{
for (std::string line; std::getline(std::cin, line); )
{
if (line.empty())
{
std::cout << "Got blank line, quitting.\n";
return 0;
}
// process line
}
std::cout << "End of input, quitting.\n";
return 0;
}
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";
This question already has an answer here:
What am I not understanding about getline+strings?
(1 answer)
Closed 7 years ago.
I've got following code:
system("CLS");
string title;
string content;
cout << "Get title." << endl;
getline(cin,title);
cout << "Get content." << endl;
getline(cin,content);
The problem is - application is not asking about tittle, I've got Get title, get content and then waiting for user input, it's not waiting for user input after get title.bDo I have to add any break or smth?
Or maybe, that isn't the best idea to read whole text line from user input?
If you have a cin >> something; call prior to your system() call.
For example, taking input into an integer. When cin >> myintvar; (or similar) then the integer is placed in myintvar and the '\n' gets sent along in the stream. The getline picks the \n up as indicative of the end of a line of input, so it is effectively "skipped".
Either change the cin >> to a getline()
or call cin.ignore() to grab the '\n'(or better, call a cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n' ); to flush the input buffer-- but be sure you're not throwing away valuable input in the process).
I'd bet that you have something like a menu for selecting options ( as a numeric type ) and after that you try to read the lines.
This happens because after std::cin read some value the remaining '\n' was not processed yet, the solution would be to include #include <limits> and then put std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
before your getline(cin,title);
It is because when you use getline() it ignores the newline at the end of the line and feeds it into the input queue, so when your getline function is called for next time it encounters the newline character discarded by the previous getline() and so it considers that as end of your input string. So thats why it doesn't take any input from you. You could use something like this
getline(cin,title);
cin.get();
hope this works.
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.