You have made a good choice to read a line at a time with getline()
, but you are controlling your read loop incorrectly. See Why !.eof() inside a loop condition is always wrong.
Instead always control the continuation of your read loop based on the stream state resulting from the read function itself. In your case, you ignore the state after getline()
and assume you have valid input -- which you won't when you read EOF
. Why?
When you read the last line in your file, you will have read input
, but the eofbit
will not yet be set as you haven't reached the end-of-file yet. You loop checking cin.eof() != true
(which it isn't yet) and then call getline (cin, input)
BAM! Nothing was read and eofbit
is now set, yet you blindly assign shape = shape + input;
even though your read with getline()
failed.
Your second issue is how do you skip empty lines? Simple. If input.size() == 0
the line was empty. To "skip" empty lines, just continue
and read the next. To "quit reading" when the first empty line is reached, replace continue
with break
.
A short example incorporating the changes above would be:
#include <iostream>
#include <string>
int main (void) {
std::string input{}, shape{};
std::size_t rows = 0;
while (getline(std::cin, input)) { /* control loop with getline */
if (input.size() == 0) /* if .size() == 0, empty line */
continue; /* get next */
shape += input; /* add input to shape */
rows++; /* increment rows */
}
std::cout << rows << " rows\n" << shape << '\n';
}
Also see: Why is “using namespace std;” considered bad practice? and avoid developing habits that will be harder to break later.
Example Use/Output
$ cat << eof | ./bin/inputshape
> ===
> ===
> ===
> eof
3 rows
=========
With a blank line at the end
$ cat << eof | ./bin/inputshape
> ===
> ===
> ===
>
> eof
3 rows
=========
Or with multiple blank lines:
$ cat << eof | ./bin/inputshape
> ===
> ===
> ===
>
>
> eof
3 rows
=========
(note: the eof
used in input above is simply the heredoc sigil marking the end of input and has no independent significance related to the stream state eofbit
or .eof()
. It could just as well have been banannas
, but EOF
or eof
are generally/traditionally used. Also, if you are not using bash or another shell supporting a heredoc, just redirect a file to the program, e.g. ./bin/inputshape < yourfile
)
Look things over and let me know if you have further questions.
Edit Based On No Use of continue
or break
If you can't use continue
or break
, then just turn the conditional around and only add to shape
if input.size() != 0
. For example:
while (getline(std::cin, input)) { /* control loop with getline */
if (input.size() != 0) { /* if .size() != 0, good line */
shape += input; /* add input to shape */
rows++; /* increment rows */
}
}
Exact same thing, just written a bit differently. Let me know if that works for you.