14

I understand that cin.eof() tests the stream format. And while giving input, end of character is not reached when there is wrong in the input. I tested this on my MSV C++ 2010 and am not understanding the strange results. No matter what I give the input, I am getting Format Error message that is present in the program.

#include <iostream>
using namespace std;

int main()
{
    int i;
    cin>> i;

    if(!cin.eof())
    {
        cout<< "\n Format Error \n";
    }
    else
    {
        cout<< "\n Correct Input \n";
    }

    getchar();
    return 0;
}

Results I expected:

Values for i =

  1. 10 => Correct Input but the output is Format Error
  2. 12a => Format Error

Could someone explain where I am going wrong. Thanks.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • 1
    See also [Semantics of flags on `basic_ios`](http://stackoverflow.com/questions/4258887/semantics-of-flags-on-basic-ios/4258924#4258924). – James McNellis Feb 08 '11 at 23:13
  • @James: I was just thinking "This needs to be made an FAQ!" when I saw it already is. Good! – sbi Feb 09 '11 at 07:34

7 Answers7

21

std::cin.eof() tests for end-of-file (hence eof), not for errors. For error checking use !std::cin.good(), the built-in conversion operator (if(std::cin)) or the boolean negation operator (if(!std::cin)).

sbi
  • 219,715
  • 46
  • 258
  • 445
  • For the input `12a` to an `int`, I am getting the message **Correct Input** when used `!std::cin.good()` – Mahesh Feb 08 '11 at 22:36
  • 1
    @Mahesch: Yep, that's because this reads the `"12"` from the input and leaves the `"a"` in the input buffer for further input operations to read. – sbi Feb 08 '11 at 22:38
  • So, how to restrict the user to input correct type? Any pre-defined function ? And in this case `!std::cin.good()` isn't serving my purpose. – Mahesh Feb 08 '11 at 22:41
  • Don't use good(), it can fail in exactly the same way eof() does! Use the stream itself (if (s), if (!s)) or the fail method (the three are equivalent, except "if (s)" is inverted). – Fred Nurk Feb 08 '11 at 22:45
  • @Fred: `good` does not fail in the way `eof` does. `eof` will be set at the end of the stream. `good` will be false whenever *any* operation occurs where the stream extraction operator could not be completed. Either `operator!`, `operator void *`, negating `good()`, or testing `fail()` will all operate correctly here. – Billy ONeal Feb 08 '11 at 22:59
  • 1
    @BillyONeal: Good will be false whenever eofbit is set even if the extraction was successfully completed. Testing good() is *not* the same as testing !fail(). – Fred Nurk Feb 08 '11 at 23:01
  • 1
    @BillyONeal: [That is wrong.](http://codepad.org/NclLtkqB) Extraction can complete successfully *and* set eofbit. – Fred Nurk Feb 08 '11 at 23:05
  • @Fred it can, but is not guaranteed to even when the file happens to end at the exact right place. See http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5 . The proper way to test is to use actual reading operations, as in (e.g.) wilx's answer. – Karl Knechtel Feb 09 '11 at 01:05
  • 1
    @KarlKnechtel: That is why my first comment here says not to use good() or eof(), but does say to test the stream itself *after* attempting extraction (since that is the context here). That is exactly what I do in my answer and also what wilx's later answer does; did you miss that first comment? – Fred Nurk Feb 09 '11 at 01:11
14

Use a direct test of the status of the stream with:

while (cin >> i)
{
    ...
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Shivendra
  • 1,542
  • 2
  • 22
  • 35
  • 5
    Welcome to Stack Overflow. Your question was marked as 'low quality' because of its extreme brevity. Although accurate, it is a good idea to provide some explanation of why your answer is correct, especially when the question was asked a long time ago (about a year ago) and there are multiple answers. Also note the `{}` icon above the editor box; that can be used to indent code snippets. – Jonathan Leffler Oct 27 '12 at 04:49
  • 1
    @JonathanLeffler thanks for the advice. Will take care of that from future answers. – Shivendra Jul 23 '17 at 15:59
7

For an input stream to enter the EOF state you have to actually make an attempt to read past the end of stream. I.e. it is not enough to reach the end-of-stream location in the stream, it is necessary to actually try to read a character past the end. This attempt will result in EOF state being activated, which in turn will make cin.eof() return true.

However, in your case you are not only not doing that, you (most likely) are not even reaching the end of stream. If you input your 10 from the keyboard, you probably finished the input by pressing the [Enter] key. This resulted in a new-line character being added to the input stream. So, what you are actually parsing with >> operator in this case is actually a 10\n sequence. Since you requested an int value from the stream, it only reads the numerical characters from the stream, i.e. it reads 1 and 0, but it stops at \n. That \n remains in the stream. You never read it. So, obviously, your code never reaches the end-of-file position in the stream. You have to reason to expect cin.eof() to become true in such case.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2
#include <iostream>

int main() {
  using namespace std;
  int i;
  if (cin >> i) {
    cout << "Extracted an int, but it is unknown if more input exists.\n";
    char c;
    if (cin.get(c)) {  // Or: cin >> c, depending on how you want to handle whitespace.
      cin.putback(c);
      cout << "More input exists.\n";
      if (c == '\n') {  // Doesn't work if you use cin >> c above.
        cout << "But this was at the end of this line.\n";
      }
    }
    else {
      cout << "No more input exists.\n";
    }
  }
  else {
    cout << "Format error.\n";
  }
  return 0;
}

Also see Testing stream.good() or !stream.eof() reads last line twice.

Sample session with the above program, note that input lines are marked with comments not present in the actual output:

$ your-program
12  # input
Extracted an int, but it is unknown if more input exists.
More input exists.
But this was at the end of this line.

$ your-program
12a  # input
Extracted an int, but it is unknown if more input exists.
More input exists.

$ echo -n 12 | your-program
Extracted an int, but it is unknown if more input exists.
No more input exists.

$ your-program
a  # input
Format error.
Community
  • 1
  • 1
Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
  • Agree with downvoter: you should test your code first. There's always at least a trailing newline to consume. – UncleBens Feb 08 '11 at 23:00
  • @UncleBens: If you want to skip whitespace, use cin >> c, as I said. But there is not always a trailing newline: `echo -n 12 | your-program` – Fred Nurk Feb 08 '11 at 23:01
  • @UncleBens: While the answer is lacking an explanation of what is going on, I cannot really agree with that statement. Compile this in a linux/osx box and run `$ echo -n 10 | ./test_app`. You can probably achieve the same in a windows terminal (or by piping a file through the program). There is *not* always a trailing new line to consume. – David Rodríguez - dribeas Feb 08 '11 at 23:05
  • It is not uncommon to use stringstreams or iostreams attached to other devices (such as the network), but echo -n is the clearest way to show this. – Fred Nurk Feb 08 '11 at 23:10
  • @David: The explanation of what is going on is in the output sent to cout. – Fred Nurk Feb 08 '11 at 23:13
  • So you mean output would have to be redirected to stdin for this to work? But in such case, wouldn't OP's code already work? - I can't see how this would work if I'm typing the value when the program asks for it. – UncleBens Feb 08 '11 at 23:21
  • @UncleBens: No, it wouldn't have to. You can signal EOF in a terminal when typing interactively. The OP's code fails with input of "a\n", whether redirected or not, and whether that newline is present or not. – Fred Nurk Feb 08 '11 at 23:24
  • You are saying that the only "correct format" would be 12[eof]? This is exactly what OP is already testing for. – UncleBens Feb 08 '11 at 23:31
  • @UncleBens: No. Only the OP knows what "correct format" means, I should've changed my output to say "extracting an int worked" rather than copying that string from the OP. For the OP "correct" could mean or but exclude , and so forth. – Fred Nurk Feb 08 '11 at 23:35
  • @UncleBens: Updated the question so you can see how this works if you're typing values as the program asks for them. – Fred Nurk Feb 08 '11 at 23:40
  • That's a lot better now. However, while we are nitpicking: why does this accept `[space]12` as input but not `12[space]`? :) – UncleBens Feb 08 '11 at 23:59
  • @UncleBens: How is it a lot better? It's unchanged except for adding a slight tweak that provides more information. – Fred Nurk Feb 09 '11 at 00:05
  • @UncleBens: This code does not accept any input (and that's why I changed "correct" to "extracted"); it rejects (some?) invalid input and shows how to determine various conditions which affect whether a particular case of extracting an int should be accepted or not. – Fred Nurk Feb 09 '11 at 00:25
  • The previous version of the code always told you that there was more input to read unless number was followed by EOF, which is pretty much useless information. – UncleBens Feb 09 '11 at 00:30
  • 1
    @UncleBens: Didn't you make the point that the OP hasn't provided enough information to decide what is and isn't correct? How do we know what's useless and what isn't without knowing the former? – Fred Nurk Feb 09 '11 at 00:32
2

Assuming your input is line based, I suggest that you read the whole line using std::getline(). Once you have the line, you can analyse it and decide whether it contains correct or wrong input. Put the line into std::istringstream and do something like the following:

Edit: Changed !! iss to static_cast<bool>(iss) for compatibility with C++0x.

std::istringstream iss (line);
char ch;
long lval;
// read the input
iss >> lval;
// result variable will contain true if the input was correct and false otherwise
result
    // check that we have read a number of at least one digit length
    = static_cast<bool>(iss)
    // check that we cannot read anything beyond the value read above
    && ! (iss >> ch);
wilx
  • 17,697
  • 6
  • 59
  • 114
  • +1 for an appropriate, robust way to do what the OP actually apparently wants to do. – Karl Knechtel Feb 09 '11 at 00:50
  • I'm sorry, but I cannot upvote anything that uses `!!`. That's what `!= 0` is for. – Billy ONeal Feb 09 '11 at 00:56
  • 1
    @BillyONeal: Comparing a stream to 0 does not make any sense. I also dislike !!, but != 0 would be worse. @wilx: bool(iss). – Fred Nurk Feb 09 '11 at 01:02
  • @Fred: The problem with casting to `bool` is that it will throw warnings on several compilers. If you don't like `!= 0` then use `fail()` explicitly. Don't use `!!`. – Billy ONeal Feb 09 '11 at 01:04
  • The description, "check that we cannot read anything beyond the value read above", does not match the code, as the code fails to distinguish between line being `"12 "` (onr or more trailing whitespace chars) and exactly "12". – Fred Nurk Feb 09 '11 at 01:05
  • @BillyONeal: Also, != 0 will fail on 0x, as the bool conversion is explicit there (and the void* conversion is removed). – Fred Nurk Feb 09 '11 at 01:07
  • @Fred: Then use `fail` explicitly. `!!` should *never* be used. – Billy ONeal Feb 09 '11 at 01:08
  • @BillyONeal: Did I say to use !!? You've told me twice not to use it and I'm not sure why. – Fred Nurk Feb 09 '11 at 01:12
  • @Fred: Sorry -- got myself a bit confused there. Was looking for a question on that and wasn't really paying as much attention as I should have. – Billy ONeal Feb 09 '11 at 01:22
  • @all: I like that because it is short and to my eyes obvious. But I have been thinking about not using it for the example here exactly because some people do not like it. :) – wilx Feb 09 '11 at 06:36
  • @Fred Nurk: I think that extra white space should not be a problem in most cases. Obviously, I cannot really read OPs thoughts but what use is it to read exactly one number from the input? – wilx Feb 09 '11 at 06:49
  • 1
    @wilx: I don't know if it's a problem either, but I do know the comments and the code disagree. – Fred Nurk Feb 09 '11 at 08:07
1

Adding to the previous answer: After reading your input (like 10), you are not at end-of-file, as you can easily type some more. How is the system to know that you will not?

When reading your second input (12a), it correctly reads all the digits that can be part of an integer. The letter 'a' cannot, so it is left for some possible later input. For example, you can read all parts of 12a with this code

int i; char c;

cin >> i >> c;

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

cin.eof() test if the stream has reached end of file which happens if you type something like Ctrl+C (on Windows), or if input has been redirected to a file etc.

To test if the input contains an integer and nothing but an integer, you can get input first into a string and then convert that with a stringstream. A stringstream indeed reaches eof if there's no more to be extracted from it.

#include <iostream>
#include <sstream>
#include <string>

int main() {
    using namespace std;
    int i;
    string input;
    cin >> input; //or getline(cin, input)
    stringstream ss(input);
    if (ss >> i && ss.eof()) {  //if conversion succeeds and there's no more to get
        cout<< "\n Correct Input \n";
    }
    else {
        cout<< "\n Format Error \n";
    }

  return 0;
}
UncleBens
  • 40,819
  • 6
  • 57
  • 90