Getting more lines from input in C++ - c++

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;
}

Related

It seems to me as if std::getline doesn't handle new lines correctly?

With the code below, I want the user to write a text in the terminal, and then print out the last sentence of the text. Maybe I should mention that I'm running on a Linux desktop.
#include <string>
#include <iostream>
int main()
{
std::string user_text{};
while(std::getline(std::cin, user_text))
{
}
std::cout << "Text: " << user_text << std::endl;
return 0;
}
Anyways if I, after running the program, write for example:
Hi my name is
And then press 'ctrl+d', the output will indeed be "Text: Hi my name is"
However if I instead do this:
Hi my name is 'press enter'
Name my is hi 'press enter'
And then press 'ctrl+d'. The output will be "Text: ". Why is this? Shouldn't getline stop when I have pressed 'ctrl+d'?
Thanks in advance!
std::getline() erases the output std::string before attempting to read from the stream.
In your second case, the first 2 calls to std::getline() have already read everything you have typed in, there is nothing left when you press CTRL-D during the 3rd call, so there is nothing for std::getline() to output into the std::string.
Save the last successful line read to a separate variable, eg:
std::string user_text, line;
while(std::getline(std::cin, line))
{
user_text = line;
}
std::cout << "Text: " << user_text << std::endl;
std::getline is working as intended: it's getting a line. If you press enter, it creates a new, empty line; if you then press ctrl+d, you're terminating std::getline, which returns that (empty) line's contents.
From the docs:
getline reads characters from an input stream and places them into a string:
Behaves as UnformattedInputFunction, except that input.gcount() is not affected. After constructing and checking the sentry object, performs the following:
Calls str.erase()
Extracts characters from input and appends them to str until one of the following occurs (checked in the order listed)
a) end-of-file condition on input, in which case, getline sets eofbit.
b) the next available input character is delim, as tested by Traits::eq(c, delim), in which case the delimiter character is extracted from input, but is not appended to str.
c) str.max_size() characters have been stored, in which case getline sets failbit and returns.
If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.
Same as getline(input, str, input.widen('\n')), that is, the default delimiter is the endline character.
Ctrl+D causes the process's read from the terminal to return immediately. If you press Ctrl+D after typing: Hi my name is, the process will read: Hi my name is. getline will not find a \n and will restart reading. Then you press Ctrl+D a second time (you didn't say it but I am sure you did). And this will interrupt the read, causing it to return 0, which is as-if the terminal was closed. getline will then return the current value: Hi my name is.
In the second case, you haven't typed anything since the last \n, so when you press Ctrl+D, read directly returns 0 and getline returns with an empty string.

Keep asking for input and reopen stdin

I have a task to create a program that does some calculation on a vector of numbers. The vector must contain at least 1 number in it and if it doesn't I have to throw an exception and try again. There is a video example how the code should work here: https://asciinema.org/a/283343
I'm guessing that EOF is being signaled using CTRL+D and that's what causes the exception to be thrown.
If they were using Enter (new line), it would leave a blank line behind.
But in my case, after I press CTRL+D, my program just runs in an infinite loop because the stdin stays in a failed state despite me using cin.clear().
Is there another shortcut similar to CTRL+D that they might be using for this, or is there a way to reopen the stream, or restart the whole application.
The program runs fine on Windows when I use CTRL+Z, but on Linux I just can't get it to work the same.
Example code below:
#include<iostream>
#include<vector>
void enter_elements(std::vector<double>& input_list){
double x;
std::cout << "Enter numbers: " << std::endl;
while(std::cin >> x){
input_list.push_back(x);
}
if(input_list.empty()){
throw std::string("You must enter at least 1 number!");
}
}
int main(){
std::vector<double> input_list;
try {
enter_elements(input_list);
} catch (const std::string& e) {
std::cout << "Error: " << e << std::endl;
std::cin.clear();
enter_elements(input_list);
}
return 0;
}
Can anyone help me with this problem or suggest where could I maybe read more about it?
No.
Once the stream is closed, the stream is closed. That's it.
What I'd do is accept a set of numbers on one line. Your input iteration would end at the end of the line. Then you validate those numbers, and ask for another line if necessary.
You can do that by looping over std::getline instead of using formatted extraction. Then you'd need to parse the line you get.
That's not what the video shows, but I don't know how they achieved that. Maybe you should ask them!
Are you asking how to stop the program?
If so, on linux, you should try CTRL+C instead of CTRL+D or CTRL+Z while your program is running
This is the sort of reason why I hate using cin >> anInt. I much prefer to getLine and parse it myself. Then you can make it do anything and decide how you're going to determine end of list, etc.
Yes, it's more code. But you don't run into these weird problems like this.

std::getline(), while loop content not running

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.

getline causes infinite loop when redirecting file to standard input

The following code simply echoes the standard input to the standard output. If I run the program like so ./a.out, I can type anything and the program works fine. However, if I run it like this ./a.out < input.txt I get an infinite loop, regardless of the content of input.txt.
#include <iostream>
using namespace std;
int main() {
string input;
while (true) {
cout << "Type your input: ";
getline(cin, input);
cout << input << endl;
}
return 0;
}
What am I doing wrong?
EDIT: To clarify, I expect that after the input from the input file is finished, getline waits for more input from stdin. Instead, it continues to read when nothing is there.
You don't have a terminating condition for your loop: while (true) is an infinite loop in any case - that is, without a break/exit/etc. in the loop body.
I'm guessing that when using your program to echo stdin you end it by pressing Ctrl-C. Run your program using ./a.out, and type Ctrl-D (EOF): you'll also get an infinite loop.
Look over the docs for getline: use the return value to end your loop:
while (getline(cin, input))
Your loop has no terminating condition, be it a break, or right inside the while part. Instead, you probably want this:
while (getline(cin, input))
That will end when the input fails, most likely resulting from having reached EOF.
What you're doing wrong is that you ignore the result of an input operation, in this case getline.
You must never ignore the result of an input operation. It is always a programming error to do so. You cannot know or make assumptions about the state of external data, so you must always check whether an input operation succeeded. If it does not, then it is generally an error to access the purported input variable for reading, so you really need to check every time, and before accessing the result.
In the present case, std::getline returns a reference to the stream object, and you can evaluate the stream as a boolean. It evaluates as true if and only if the extraction succeeded; otherwise, you must not use the result (and presumably stop reading).
All in all, the code should go like this:
for (std::string line; std::getline(std::cin, line); )
{
// use "line"
}

functionality of cin in c++

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.