What will happen if the input stream is invalid? For example, as follows:
int main()
{
int value;
while(!(cin>>value).eof());
}
If the entered sequence is : 1 2 3 q 4 5, the while will fall into endless loop when the cin scans 'q' and the value continues to be 3.
My questions are:
1. Why can't cin ignore 'q' and proceed to scan 4?
2. What's the underlying implementation fo input stream? Are there any materials I can refer to ?
Thank you!
Why can't cin ignore 'q' and proceed to scan 4?
You can if you want to. You could get that effect with the following:
int value;
while(std::cin>>value);
if (!std::cin)
{
std::cin.clear(); // clear error state
std::cin.ignore(); // ignore the q
while(std::cin>>value); // read rest of values until 5
}
std::cin >> value just does not do that by default, as the behavior desired is different depending on the program. For many people it would be undesirable for std::cin to ignore a read failure and keep scanning. The default behavior allows you the programmer to decide what to do on failure.
Also, note that eof() is for checking for end of file. You should not use it to check if a read was successful or not. The common idiom would be:
while(std::cin>>value)
{
// Do stuff
}
What's the underlying implementation fo input stream? Are there any materials I can refer to ?
std::cin is a global static object and is defined like so:
extern std::istream cin;
In other words it is an instance of std::basic_istream<char> (std::istream is a typedef for it).
If you would like more information, here are some references:
http://en.cppreference.com/w/cpp/io/cin
https://github.com/cplusplus/draft
However, most likely you would benefit from a good C++ book.
If you want to get into deep iostreams, I also recommend these articles.
Related
I'm a really anxious person that I can't move on in learning new subject unless I completely understand the current one, and when I'm stuck at some object I would keep looking for resources for ages trying to sort it out even with very trivial ones.
I'm learning C++. I finished the basics, and now I'm moving on to the intermediate level; In the I/O libraries there is a big drawback that I can't understand. When the std::cin object is not valid to get new input due to EOFBIT or FAILBIT as in :
*** #include <iosteam>
int main()
{
int ival; // declaring an integer
std::cin >> ival; // defining ival from the std input
std::cin >> ival; // redefining ival ...
}***
If we hit a char type for the first input, the stream becomes invalid and we won't be able to use the std::cin again in any further point in the program.
Are there any solution to re-validate stream again?? , if there is not, Can we create input stream objects other than std::cin?
std::cin is a global instance of type std::istream. You can create other instances of std::istream if you like. However, to clear the error flags you can call clear inherited from std::basic_ios.
I usually teach my students that the safe way to tackle file input is:
while (true) {
// Try to read
if (/* failure check */) {
break;
}
// Use what you read
}
This saved me and many people from the classical and most of the time wrong:
while (!is.eof()) {
// Try to read
// Use what you read
}
But people really like this form of looping, so it has become common to see this in student code:
while (is.peek()!=EOF) { // <-- I know this is not C++ style, but this is how it is usually written
// Try to read
// Use what you read
}
Now the question is: is there a problem with this code? Are there corner cases in which things don't work exactly as expected? Ok, it's two questions.
EDIT FOR ADDITIONAL DETAILS: during exams you sometimes guarantee the students that the file will be correctly formatted, so they don't need to do all the checks and just need to verify if there's more data. And most of the time we deal with binary formats, which allow you to not worry about whitespace at all (because the data is all meaningful).
While the accepted answer is totally clear and correct, I'd still like someone to try to comment on the joint behavior of peek() and unget().
The unget() stuff came to my mind because I once observed (I believe it was on Windows) that by peeking at the 4096 internal buffer limit (so effectively causing a new buffer to be loaded), ungetting the previous byte (last of the previous buffer) failed. But I can be wrong. So that was my additional doubt: something known I missed, which maybe is well coded in the standard or in some library implementations.
is.peek()!=EOF tells you whether there are still characters left in the input stream, but it doesn't tell you whether your next read will succeed:
while (is.peek()!=EOF) {
int a;
is >> a;
// Still need to test `is` to verify that the read succeeded
}
is >> a could fail for a number of reasons, e.g. the input might not actually be a number.
So there is no point to this if you could instead do
int a;
while (is >> a) { // reads until failure of any kind
// use `a`
}
or, maybe better:
for (int a; is >> a;) { // reads until failure of any kind
// use `a`
}
or your first example, in which case the is.peek()!=EOF in the loop will become redundant.
This is assuming you want the loop to exit on every failure, following your first code example, not only on end-of-file.
So recently I've learned that using .eof can be considered a kind of big no no and I want to start moving away from it. One of the main substitutions I have seen is using
while(inFile >> num)
{
}
However, when I do this using arrays it only stores the first input and nothing else. Any tips?
Example:
while(inMovie >> title[x])
{
inMovie >> income[x];
x++;
}
What you really want to be doing is:
while ((inMovie >> title[x]) && (inMovie >> income[x]))
{
x++;
}
Or, more succinctly:
while (inMovie >> title[x] >> income[x])
{
x++;
}
This way, both input operations have to "succeed" in order for you to continue.
That being said, there is nothing inherently broken with your attempt, and there is no reason for it to "only store the first input" as long as the input is correct.
Check your input.
I'm also concerned that you may not be using arrays properly. Does your array have enough space for all these elements? Or are you expecting title and income to expand automatically? Because they won't do that. In that case, your program has undefined behaviour (which may produce all sorts of weird results!) and you should consider using a vector instead.
I would like to test if a std::istream has reached the end without reading from it.
I know that I can check for EOF like this:
if (is >> something)
but this has a series of problems. Imagine there are many, possibly virtual, methods/functions which expect std::istream& passed as an argument.
This would mean I have to do the "housework" of checking for EOF in each of them, possibly with different type of something variable, or create some weird wrapper which would handle the scenario of calling the input methods.
All I need to do is:
if (!IsEof(is)) Input(is);
the method IsEof should guarantee that the stream is not changed for reading, so that the above line is equivalent to:
Input(is)
as regards the data read in the Input method.
If there is no generic solution which would word for and std::istream, is there any way to do this for std::ifstream or cin?
EDIT:
In other words, the following assert should always pass:
while (!IsEof(is)) {
int something;
assert(is >> something);
}
The istream class has an eof bit that can be checked by using the is.eof() member.
Edit: So you want to see if the next character is the EOF marker without removing it from the stream? if (is.peek() == EOF) is probably what you want then. See the documentation for istream::peek
That's impossible. How is the IsEof function supposed to know that the next item you intend to read is an int?
Should the following also not trigger any asserts?
while(!IsEof(in))
{
int x;
double y;
if( rand() % 2 == 0 )
{
assert(in >> x);
} else {
assert(in >> y);
}
}
That said, you can use the exceptions method to keep the "house-keeping' in one place.
Instead of
if(IsEof(is)) Input(is)
try
is.exceptions( ifstream::eofbit /* | ifstream::failbit etc. if you like */ )
try {
Input(is);
} catch(const ifstream::failure& ) {
}
It doesn't stop you from reading before it's "too late", but it does obviate the need to have if(is >> x) if(is >> y) etc. in all the functions.
Normally,
if (std::is)
{
}
is enough. There is also .good(), .bad(), .fail() for more exact information
Here is a reference link: http://www.cplusplus.com/reference/iostream/istream/
There are good reasons for which there is no isEof function: it is hard to specify in an usable way. For instance, operator>> usually begin by skipping white spaces (depending on a flag) while some other input functions are able to read space. How would you isEof() handle the situation? Begin by skipping spaces or not? Would it depend on the flag used by operator>> or not? Would it restore the white spaces in the stream or not?
My advice is use the standard idiom and characterize input failure instead of trying to predict only one cause of them: you'd still need to characterize and handle the others.
No, in the general case there is no way of knowing if the next read operation will reach eof.
If the stream is connected to a keyboard, the EOF condition is that I will type Ctrl+Z/Ctrl+D at the next prompt. How would IsEof(is) detect that?
I'm attempting to construct a function that will perform a sanity check on the user's response to a number of questions, each of which would ideally be a non-zero integer. How can I construct a function that would be able to accept a parameter of any data type, but only have a single parameter? For example:
bool SanityCheck(<type id> number)
where <type id> would cover any data type.
It's not clear exactly what you really want here. Unverified input from a user normally comes in the form of a string. Typically you read in a string, verify that it has the desired form (e.g., for an integer, all digits). If it has the right form, you convert that to the desired type, and use it. If it doesn't, you ask the user to re-enter their data, usually with a prompt like "Please enter an integer between 1 and 10".
A function template is sort of a direct answer to the question you asked, but I have a hard time imagining it being of any help in a situation like you've described. A function template is most often of use in cases where you have to carry out some operations that are syntactically the same across a number of types. For example, it lets you add two numbers, regardless of whether those happen to be of type short, int, long, float, double, long double, etc. That only works because they're really all numbers, and you can reasonably use + to add any of them together.
When you're dealing with some unknown input, that doesn't apply though -- you need to verify enough about the data to be sure the operation is sensible and meaningful before you can do much else with it; it's pretty hard to get a meaningful result from comparing (for example) 7 to a sunset.
C++ is a statically typed language. What type a variable is of will be fixed at compile-time and cannot be changed at run-time. What users enter, however, will only be known at run-time, and cannot be known at compile-time. Therefore your question makes no sense.
When you expect an integer from a user, then the best way would be to try to read an integer, and check whether this succeeds:
int i;
std::cin >> i;
if(!std::cin)
throw "Stupid user blew it!"; // or some real error handling
However, the catch with this is that, once an input operation fails, an input stream enters a bad state and the data that couldn't be read stays in the input buffer. If you want to handle this gracefully, would have to clear the stream's error state flags, and make it ignore whatever is in the input buffer.
So sometimes it might be easier to first read a string
std::string input;
std::cin >> input; // either read up to any whitespace, or
std::getline(std::cin, input); // newline, or
std::getline(std::cin, input, '\t'); // tab, or whatever you want
because this always succeeds, and then try to convert it into whatever data you need. The way to do this is via string streams:
std::istringstream iss(input);
int i;
iss >> i;
Now you can check the string stream's state
if(!iss)
and if the conversion failed, std::cin will still be usable and the erroneous input read from its buffer.
However, there's one more catch: If a user inputs '"42 thousand"', then this won't catch the error. The remaining characters will be in the string streams input buffer and silently ignored. So what you usually need to do for such a conversion is to test whether the string stream's buffer is fully read, that is: reading reached EOF. You can check for this by invoking iss.eof(). However, if you read a whole line, there might be extra whitespace at the end, which you wouldn't want to make the conversion fail, so you need to read extra whitespace before you check for EOF: iss >> std::ws. (std::ws is a stream manipulator that "eats" consecutive whitespaces.)
by now, the conversion would look like this:
std::istringstream iss(input);
int i;
iss >> i >> std::ws; // you can chain input
if(!iss.eof())
throw invalid_input(input);
Of course, this is pretty elaborated for a one-time conversion and I wouldn't exactly swear by the life of my kids that there isn't a nice improvement left that I hadn't thought of yet. So you would at least want to wrap this into a function and put that into your toolbox for reusing it (and improving on it, if you find an error):
bool convert_to_int(const std::string& str, int& result)
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Or, generic for any type:
template< typename T >
bool convert_from_string(const std::string& str, T& result
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Even better would be to use a ready-made off-the-shelf solution for this. Boost has just such a thing with its lexical_cast.
Here's a skeleton algorithm for the whole input routine:
int i;
do {
read string input
convert to int i
while(!conversion succeeded);
With the bits from further above, you should be able to fill in the missing parts.
Use templates:
template <typename T>
bool SanityCheck(T number);
The sanity check may vary for different types. As this is a homework, I won't post any more code just hint you with a Google search term "partial template specialization".
Ok, I think I get what you actually want now.
I imagine your situation is something like this:
Read some user input (maybe using std::cin).
Check to make sure it is an int.
Use the int if it is one.
If this is the case then you do not want a function that can handle different data types, because the user cannot enter different data types, he can only enter characters and you have to choose what datatype you want to store that as.
I think this is what you need:
bool valid = false;
int input = 0;
while (!valid)
{
std::string inputStr;
std::cin >> inputStr;
valid = isInteger(inputStr);
if (!valid)
std::cout << "Please enter an integer." << std::endl;
else
input = atoi(inputStr.c_str());
}
std::cout << "You entered " << input << "!" << std::endl;
You're going to have to write isInteger yourself, but hopefully you get the idea.
Option 1: use boost::variant if you want it to be a single function
Option 2: overload this function for all types that you need
Making your function a template function would achieve this.
template<typename T>
bool SanityCheck(T number);
A lot of online surveys that I'm asked to fill out don't ask me to enter data but only select an option from 1 to 5. 1 = Totally Agree, 5 = Totally Disagree. This seems a more efficient way of collecting user input since you have total control over data type and all I have to do is highlight an option box.