getline not working on second call - c++

The second while doesn't work. I tried filestr.clear()/flush() and others with no result. If I comment the first while everything is OK, but I need the number of objects. Somebody help, please
while (std::getline(filestr, line)) {
if (line.find("<rect") != std::string::npos) count_rect++;
}
rect = new Rectangle[count_rect];
while (std::getline(filestr, line1)) {
//code
}

The first loop extracts lines from filestr until there's nothing left to read.
It's hard to concieve why you think a second loop will then find more lines. If the second loop had any input to read, the first loop would already have read it.
I cannot confidently suggest a fix because you did not tell us what your code is supposed to do instead. However, assuming filestr is a file stream, you may wish to move the read cursor to the beginning after your clear operation:
filestr.clear(); // clear any state flags
filestr.seekg(0, ios::beg); // move cursor to start so we read everything again
If filestr is poorly named and actually represents a non-file stream, you can't do this and will need a fresh approach to your pre-scanning algorithm.
Also, you should avoid new in favour of std::vector. And you should indent your code properly instead of making a mess.

Related

Empty input variable that failed C++

I've found many posts saying I should be using the following code to empty the input variable in order to reset it:
cin.ignore(numeric_limits<streamsize>::max(), '\n');
But what am I missing here since it's not compiling, it says expected an identifier when mouse hover over max();
code:
int Menu::getInput()
{
int choice;
cin >> choice;
if (cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return choice = 3;
}
return choice;
}
The suggestions that you've read to use ignore() are just band-aids designed to workaround broken logic that attempts to read newline delimited text using operator>>.
The general situation goes something like this: "well, I should be reading lines of text that contain two integers, followed by a text string, ok, so I'll use operator>> to read two integers, then a std::string, from std::cin". And that's fine, as long as we all live in a perfect world. Unfortunately, we don't live in a perfect world, and when bad input is encountered, in the middle of this odyssey, we end up with:
A std::istream in an error/fail state.
An undeterminate amount of consumed input, with a partially read line.
Recovering from this mess is what the using ignore() is supposed to achieve, by reading and discarding the remainder of the partially-consumed line, until the next newline characters.
But wouldn't you agree that it's much better not end up in this ugly mess to start with, in the first place?
And that's why if you need to read something that's formatted as lines of text, you should simply use std::getline(), to read one line of text at time. What a novel idea!
And then, once you've read the next line of text into a simple, std::string buffer, if you feel like it you can go ahead and construct a std::istringstream object from it, and use operator>> to your heart's content.
And if parsing the line of text, using std::istringstream, fails for some reason, you only need to issue an appropriate complaint to the user, then simply loop back, and use std::getline() to read the next line of text from your input time, without having to screw around with resetting the stream's status, or discarding partially-processed line. That seems to me like a much simpler, easier approach, doesn't it?
It appears to me that most C++ courses, instructors, and textbooks, are doing a disservice to their students by unceremoniously sprinkling liberal usage of operator>>, without properly explaining that this is a completely wrong approach to reading input that's formatted as newline-delimited lines of text. This just leads to nothing but utter confusion, and buggy code.
Take this as an answer to your question: scrap completely what you're doing, and simply rewrite it, simply as:
int Menu::getInput()
{
int choice;
std::string buffer;
if (!std::getline(std::cin, buffer).eof())
{
std::istringstream i(buffer);
i >> choice;
if (!i.fail())
return choice;
}
return 3;
}
Money back guarantee: this approach guarantees to never mess up your std::cin's state, or leave it with partially-consumed input.

Reading a text file from the first line multiple times (C++)

I'm using "getline" to read some lines in a text file. It works as it should, but I'm calling the method multiple times.
while(getline(file, line))
{
//Do something
}
//More code in between
while(getline(file, line))
{
//Do something else
}
The problem is that when I call "getline" the second time it starts reading from where it previously finished (e.g. If the first while loop ends at the second line then the next loop starts at the third line). How can I ensure that my program reads the file from the first line every time?
If you need that same first line multiple times I think you should reconsider your strategy.
Just read the line once.
Save it in a variable (or just keep it in the variable "line" you already have).
Close the file.
You would avoid a lot of not necessary I/O operations...
Nonetheless as other people suggested if by any reason you want to procede with this approach you need to insert:
myinputstream.clear(); //clear the buffer
myinputstream.seekg(0, ios::beg); //reset the reading position to beginning
between each attempt to read the same file.
And do not forget to close it eventually.
myinputstream.close();
There's a seekg() function that should help
http://www.cplusplus.com/reference/istream/istream/seekg/
iostream::seekg (0, iostream::beg);
will move you at the beggining of the stream

Difference between while(!file.eof()) and while(file >> variable)

First things first - I've got a text file in which there are binary numbers, one number for each row. I'm trying to read them and sum them up in a C++ program. I've written a function which transforms them to decimal and adds them after that and I know for sure that function's ok. And here's my problem - for these two different ways of reading a text file, I get different results (and only one of these results is right) [my function is decimal()]:
ifstream file;
file.open("sample.txt");
int sum = 0;
string BinaryNumber;
while (!file.eof()){
file >> BinaryNumber;
sum+=decimal(BinaryNumber);
}
and that way my sum is too large, but by a small quantity.
ifstream file;
file.open("sample.txt");
int sum = 0;
string BinaryNumber;
while (file >> BinaryNumber){
sum+=decimal(BinaryNumber);
}
and this way gives me the the right sum. After some testing I came to a conclusion that the while loop with eof() is making one more iteration than the other while loop. So my question is - what is the difference between those two ways of reading from a text file? Why the first while loop gives me the wrong result and what may be this extra iteration that it's doing?
The difference is that >> reads the data first, and then tells you whether it has been a success or not, while file.eof() does the check prior to the reading. That is why you get an extra read with the file.eof() approach, and that read is invalid.
You can modify the file.eof() code to make it work by moving the check to a place after the read, like this:
// This code has a problem, too!
while (true) { // We do not know if it's EOF until we try to read
file >> BinaryNumber; // Try reading first
if (file.eof()) { // Now it's OK to check for EOF
break; // We're at the end of file - exit the loop
}
sum+=decimal(BinaryNumber);
}
However, this code would break if there is no delimiter following the last data entry. So your second approach (i.e. checking the result of >>) is the correct one.
EDIT: This post was edited in response to this comment.
When using file.eof() to test the input, the last input probably fails and the value stays unchanged and is, thus, processed twice: when reading a string, the stream first skips leading whitespace and then reads characters until it finds a space. Assuming the last value is followed by a newline, the stream hasn't touched EOF, yet, i.e., file.eof() isn't true but reading a string fails because there are no non-whitespace characters.
When using file >> value the operation is executed and checked for success: always use this approach! The use of eof() is only to determine whether the failure to read was due to EOF being hit or something else.

What is the "right" way to read a file with C++ fstreams?

I am using the standard C++ fstreams library and I am wondering what is the right way to use it. By experience I sort of figured out a small usage protocol, but I am not really sure about it. For the sake of simplicity let's assume that I just want to read a file, e.g., to filter its content and put it on another file. My routine is roughly as follows:
I declare a local istream i("filename") variable to open the file;
I check either i.good() or i.is_open() to handle the case where something went bad when opening, e.g., because the file does not exist; after, I assume that the file exists and that i is ok;
I call i.peek() and then again i.good() or i.eof() to rule out the case where the file is empty; after, I assume that I have actually something to read;
I use >> or whatever to read the file's content, and eof() to check that I am over;
I do not explicitly close the file - I rely on RAII and keep my methods as short and coherent as I can.
Is it a sane (correct, minimal) routine? In the negative case, how would you fix it? Please note that I am not considering races - synchronization is a different affair.
I would eliminate the peek/good/eof (your third step). Simply attempt to read your data, and check whether the attempted read succeeded or failed. Likewise, in the fourth step, just check whether your attempted read succeeded or not.
Typical code would be something like:
std::ifstream i("whatever");
if (!i)
error("opening file");
while (i >> your_data)
process(your_data);
if (!i.eof())
// reading failed before end of file
It's simpler than you have described. The first two steps are fine (but the second is not necessary if you follow the rest of my advice). Then you should attempt extraction, but use the extraction as the condition of a loop or if statement. If, for example, the file is formatted as a series of lines (or other delimited sequences) all of the same format, you could do:
std::string line;
while (std::getline(i, line)) {
// Parse line
}
The body of the loop will only execute if the line extraction works. Of course, you will need to check the validity of the line inside the loop.
If you have a certain series of extractions or other operations to do on the stream, you can place them in an if condition like so:
if (i >> some_string &&
i.get() == '-' &&
i >> some_int) {
// Use some_string and some_int
}
If this first extraction fails, the i.ignore() not execute due to short-circuit evaluation of &&. The body of the if statement will only execute if both extractions succeed. If you have two extractions together, you can of course chain them:
if (i >> some_string >> some_int) {
// Use some_string and some_int
}
The second extraction in the chain will not occur if the first one fails. A failed extraction puts the stream in a state in which all following extractions also fail automatically.
For this reason, it's also fine to place the stream operations outside of the if condition and then check the state of the stream:
i >> some_string >> some_int;
if (i) {
// Use some_string and some_int
}
With both of these methods, you don't have to check for certain problems with the stream. Checking the stream for eof() doesn't necessarily mean that the next read will fail. A common case is when people use the following incorrect extraction loop:
// DO NOT DO THIS
while (!i.eof()) {
std::getline(i, line)
// Do something with line
}
Most text files end with an extra new line at the end that text editors hide from you. When you're reading lines from the text file, for the last iteration you haven't yet hit the end of file because there's still a \n to read. So the loop continues, attempts to extract the next line which doesn't exist and screws up. People often observe this as "reading the last line of the file twice".

std::getline and eol vs eof

I've got a program that is tailing a growing file.
I'm trying to avoid grabbing a partial line from the file (e.g. reading before the line is completely written by the other process.) I know it's happening in my code, so I'm trying to catch it specifically.
Is there a sane way to do this?
Here's what I'm trying:
if (getline (stream, logbuffer))
{
if (stream.eof())
{
cout << "Partial line found!" << endl;
return false;
}
return true;
}
return false;
However, I can't easily reproduce the problem so I'm not sure I'm detecting it with this code. std::getline strips off newlines, so I can't check the buffer for a trailing newline. My log message (above) is NEVER tripping.
Is there some other way of trying to check what I want to detect? Is there a way to know if the last line I read hit EOF without finding a EOL character?
Thanks.
This will never be true:
if (getline (stream, logbuffer))
{
if (stream.eof())
{
/// will never get here
If getline() worked, the stream cannot be in an eof state. The eof() and related state tests only work on the results of a previous read operation such as getline()- they do not predict what the next read will do.
As far as I know, there is no way of doing what you want. However, if the other process writes a line at a time, the problems you say you are experiencing should be very rare (non -existent in my experience), depending to some extent on the OS you are are using. I suspect the problem lies elsewhere, probably in your code. Tailing a file is a very common thing to do, and one does not normally need to resort to special code to do it.
However, should you find you do need to read partial lines, the basic algorithm is as follows:
forever do
wait for file change
read all possible input using read or readsome (not getline)
chop input into lines and possible partial line
process as required
end
An istream object such as std::cin has a get function that stops reading when it gets to a newline without extracting it from the stream. You could then peek() or get() it to see if indeed it is a newline. The catch is that you have to know the maximum length of a line coming from the other application. Example (untested) code follows below:
char buf[81]; // assumes an 80-char line length + null char
memset(buf, 0, 81);
if (cin.get(buf, 81))
{
if (cin.peek() == EOF) // You ran out of data before hitting end of line
{
cout << "Partial line found!\n";
}
}
I have to take issue with one statement you made here:
However, I can't easily reproduce the problem so I'm not sure I'm detecting it with this code.
It seems like from what you said it would be extremely easy to replicate your problem, if it is what you said. You can easily create a text file in some text editor - just make sure that the last like ends in an EOF instead of going on to a new line. Then point your program at that file and see what results.
Even if the other program isn't done writing the file, in the file that's where the line ends, so there's no way to tell the difference other than waiting to see if the other program writes something new.
edit: If you just want to tell if the line ends in a newline or not, you could write your own getline function that reads until it hits a newline but doesn't strip it.