Why istringstream appends '-1' character at the end of stream? - c++

I've noticed that when I'm using istringstream eof() doesn't return true even if the whole string is "consumed". For example:
char ch;
istringstream ss{ "0" };
ss >> ch;
cout << ss.peek() << " " << (ss.eof() ? "true" : "false");
Outputs(VS2015):
-1 false

eof() isn't supposed to return true when all the data is consumed. It's supposed to return true when you attempt to read more data than is available.
In this example, you never do that.
In particular, peek is a "request", that won't set EOF even when there's nothing left to read; because you're, well, peeking. However, it will return the value of the macro EOF (commonly -1), which is what you're seeing when you output peek()'s result. Nothing is "appended" to the stream.
Read the documentation for functions that you use.

std::istream::peek
Peek next character Returns the next character in the input sequence,
without extracting it: The character is left as the next character to
be extracted from the stream.
If any internal state flags is already set before the call or is set
during the call, the function returns the end-of-file value (EOF).
http://www.cplusplus.com/reference/istream/istream/peek/

Related

std::getline is reading line where specified delimiter is not present?

I want to print each object in console from the array of the following string (stored in a file):
{ beforechars [{Object1},{Object2},{Object3}] afterchars }
I'm doing it as follows:
std::ifstream is("content.txt");
std::getline(is, content, '[');
while (std::getline(is,content,'{')) {
std::getline(is,content,'}');
std::cout << content << std::endl;
}
in.close();
But i am getting this output:
Object1
Object2
Object3
] afterchars }
My understanding is that after Object3 iteration, the ifstream should have "}] afterchars }" and the while's guard shouldn't be true because there isn't any '{' char... Am i right? Where is the mistake?
The while condition doesn't work as you expect: getline() will read successfully until it reaches an '{' or to the end of the file if not.
So what happens here ?
when you've displayed Object3 your position in the stream is after the closing '}'.
The getline() in the while condition will read all the remaining of the file into content as it encounters no '{'. As it could read something successfully, the condition is evaluated to true.
the getline() within the while block then fails to read anything, so content will remain unchanged. The stream is then in fail status. No subsequent operation will succeed until you clear this state. But nothing visible happens for now in your code.
after displaying this last result, the next loop condition will fail.
Simple workaround:
A very easy workaround would be to keep the current position in the stream before looking for '{', and in case it was not found, go back to this position. Attention: this way of parsing files is not so nice from point of view of performance, but it's ok for small files.
std::getline(is, content, '[');
auto pos = is.tellg(); // read current position
while (std::getline(is,content,'{') && !is.eof()) {
std::getline(is,content,'}');
pos = is.tellg(); // update position before iterating again
std::cout << content << std::endl;
}
is.seekg(pos); // and get back to last position
The trick here is that if '{' is not found, after the getline() the stream is not yet in fail state, but eof() is already true. We can then end the loop and go back to the last recorded position.
Online demo
std::getline reads characters until delimiter (consuming it) or until the end of the stream. It sets failbit on stream only if there were no character consumed (called on empty/invalid stream).
So your loop will terminate only when stream is empty.
Streams interface allows only to see next character, there is no way to scan input and do read if there specific character present.
If you need random access to characters, you need to read input in string and then parse it (with regular expressions or something else.)

C++ Read in file with only numbers (doubles)

I'm trying to read in a file that should contain only numbers in it. I can successfully read in the entire file if it meets that criteria, but if it so happened to have a letter in it, I need to return false with an error statement.
The problem is I'm finding it hard for my program to error when it finds this character. It can find it no problem, but when it does, it decides to just skip over it.
My code to read in the file and attempt to read in only numbers:
bool compute::Read (ifstream& stream)
{
double value;
string line;
int lineNumber = 1;
if (stream)
{
while (getline(stream, line))
{
lineNumber++;
istringstream strStream(line);
while (strStream >> value)
{
cout << value << endl;
}
}
}
return true;
}
The input file which I use for this is
70.5 61.2 A8 10.2
2
Notice that there is a non-number character in my input file. It should fail and return false at that point.
Currently, all it does is once it hits the "A", it simply returns to the next line, continuing the getline while loop.
Any help with this would be much appreciated.
The stringstream does catch those errors, but you're doing nothing to stop the enclosing loop from continuing when an error is found. You need to tailor your main loop so that it stops when the stringstream finds an error, which you can't do if the stringstream is being reconstructed on each iteration. You should create a for() loop instead and construct the stringstream in the declaration part. And the condition to the loop should be "as long as the stringstream and stream do not catch an error". For example:
for (std::istringstream iss; iss && std::getline(stream, line);)
{
iss.clear();
iss.str(line);
while (iss >> value)
{
std::cout << value << '\n';
}
}
Futhermore, it doesn't look like you need to use std::getline() or std::istringstream if you just want to print each value. Just do:
while (stream >> value) {
std::cout << value << '\n';
}
The above will stop when it finds an invalid character for a double.
You need the code to stop streaming but return false if it hasn't yet reached the end of the "input".
One way, possibly not the most efficient but still one way, to do that is parse a word at a time.
If you read first into a std::string and if it works (so the string is not empty) create an istringstream from that string, or reuse an existing one, and try streaming that into a double value.
If that fails, you have an invalid character.
Of course you can read a line at a time from the file, then split that into words, so that you can output a meaningful error message showing what line the bad text was found.
The issue of reading straight into doubles is that the stream will fail when it reaches end of file.
However it is possible to workaround that too because the reason for failing has an error status which you can check, i.e. you can check if it eofbit is set. Although the f in eofbit stands for "file" it applies to any stream not just files.
Although this method may sound better than reading words into a string first, I prefer that method in normal circumstances because you want to be able to report the error so you'll want to print in the error what was read.

ifstream eof function (C++)

I have this code:
string a = "D:\\Users\\user-pc\\Desktop\\testing\\a.txt";
ifstream f;
/*edit*/ string line;
/*edit*/ getline(f, line);
f.open(a);
if ( f.eof() )
cout << "ended";
else
cout << "nope"
and the file 'a.txt' which has nothing in it.
the output is nope, alway nope. I don't get it.. Do I use it wrong?
EDIT: still .eof() not working
std::basic_istream<...>::eof() only returns true if a recent extraction set the appropriate bit in the stream state. When a file stream is constructed, its stream state is always that of std::ios_base::goodbit.
An alternative is to check if the next available character is the EOF character:
if (f.peek() == std::char_traits<char>::eof())
eofbit error state flag is only set once a read tries to read past the end of the file.

cin.getline sets the begin of a string a '\0'

I run this piece of code on Visual C++ 2010
char c[10];
cin.get(&c[0],5);
cin.get(&c[2],4);
cout << c << endl;
and if I feed "123456789" to cin, the cout clause will print "12567", which is the result I expected.
But if I write:
char c[10];
cin.getline(&c[0],5);
cin.getline(&c[2],4);
cout<< c <<endl;
and feed the same string, it will only show me "12", where c=={'1','2','\0','4','\0'}
According to the documentation, the difference between cin.get and cin.getline is that cin.get does not discard the delim character as cin.getline does, so I don't know why this happens. Can anyone give me hints?
What is happening is that if basic_iostream::getline() reaches the limit of characters to be read (the streamsize argument minus 1), it stops reading then places a null character after the data it has read so far. It also sets the failbit on the stream.
So assuming that the stream has "123456789" ready to read, when you call cin.get(&c[0],5) the array will get {'1','2','3','4','\0'} placed into elements 0 through 4. And the failbit is set on the stream.
Now when you call cin.get(&c[2],4), the failbit is set on the stream, so nothing is read. The getline() call does nothing but place the terminating null into the array at index 2 (even if nothing is read from the stream, getline() will place the null character - even if the non--read is because of the failbit). So the array now looks like:
{'1','2','\0','4','\0'}
The documentation you link to mentions this:
If the function stops reading because this size is reached, the failbit internal flag is set.
But getline() does a lot, so it's easy to miss that detail.

How does ifstream's eof() work?

#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "\n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "\n";
}
return 0;
}
I'm really confused about eof() function. Suppose that my ex.txt's content was:
abc
It always reads an extra character and shows -1 when reading using eof(). But the inf >> c gave the correct output which was 'abc'? Can anyone help me explain this?
-1 is get's way of saying you've reached the end of file. Compare it using the std::char_traits<char>::eof() (or std::istream::traits_type::eof()) - avoid -1, it's a magic number. (Although the other one is a bit verbose - you can always just call istream::eof)
The EOF flag is only set once a read tries to read past the end of the file. If I have a 3 byte file, and I only read 3 bytes, EOF is false, because I've not tried to read past the end of the file yet. While this seems confusing for files, which typically know their size, EOF is not known until a read is attempted on some devices, such as pipes and network sockets.
The second example works as inf >> foo will always return inf, with the side effect of attempt to read something and store it in foo. inf, in an if or while, will evaluate to true if the file is "good": no errors, no EOF. Thus, when a read fails, inf evaulates to false, and your loop properly aborts. However, take this common error:
while(!inf.eof()) // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}
However, this:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
Which is what we want.
The EOF flag is only set after a read operation attempts to read past the end of the file. get() is returning the symbolic constant traits::eof() (which just happens to equal -1) because it reached the end of the file and could not read any more data, and only at that point will eof() be true. If you want to check for this condition, you can do something like the following:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
iostream doesn't know it's at the end of the file until it tries to read that first character past the end of the file.
The sample code at cplusplus.com says to do it like this: (But you shouldn't actually do it this way)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
A better idiom is to move the read into the loop condition, like so:
(You can do this with all istream read operations that return *this, including the >> operator)
char c;
while(is.get(c))
cout << c;
eof() checks the eofbit in the stream state.
On each read operation, if the position is at the end of stream and more data has to be read, eofbit is set to true. Therefore you're going to get an extra character before you get eofbit=1.
The correct way is to check whether the eof was reached (or, whether the read operation succeeded) after the reading operation. This is what your second version does - you do a read operation, and then use the resulting stream object reference (which >> returns) as a boolean value, which results in check for fail().