use of: while (cin >> x) and eof

2020-08-01 05:33发布

问题:

I am not so sure how the works I suppose is my root problem here. I've read a few previous posts on while(cin>>x) but nothing seems to answer my question really. I am using this loop to read in some text data:

while (cin >> x){
    searchText.push_back(x);
}

but then later in the code I am trying to read in a single word using:

cout << "Please enter your target word: ";
string targetWord;
cin >> targetWord;

but the above while loop/ eof seems to scupper the 2nd code snippet (if I move the 2nd code snippet up above it all works fine, but obviously that is not what im trying to do)

EDIT Here is the full code for clarity:

int main()
{
// ask for the target word
//   cout << "Please enter your target word: ";
//   string targetWord;
//   cin >> targetWord;

   // ask for and read the search text
   cout <<  "Enter the complete search text, "
            "followed by end-of-file: ";
   vector<string> searchText;
   string x;
   while (cin >> x){
      searchText.push_back(x);
   }

   // check that some text was entered
   typedef vector<string>::size_type vec_sz;
   vec_sz size = searchText.size();
   if (size == 0){
      cout << endl <<   "You must enter some text. "
                        "Please try again." << endl;
      return 1;
   }

// ask for the target word
   cin.clear();
   cout << "";
   cout << "Please enter your target word: ";
   string targetWord;
   cin >> targetWord;


   int count = 0;
   for (int i=0; i<size; ++i){
      if (targetWord == searchText[i]){
      count++;
      }
   }

   cout  << "The target word [" << targetWord << "] was "
            "in the search text " << count << " times." << endl;

   return 0;
}

I am just trying to take in some text from the user... then a search word and see how many times the word appears in the entered text (pretty simple!)

I know I could do it differently but the question here is more about how can I use the cout/ cin stream again after it has had an EOF in it previously

回答1:

When cin (or any other std::stream) hits an end of file, it sets a status to indicate that this has happened.

To reset this status, you need to call cin.clear();, which will clear any "bad" state, and make sure the stream is "ok" to use again. This also applies if you are reading from a file, and want to restart from the beginning.

Edit: I just took the code posted above, and ran it on my machine, adding at the top

#include <iostream>
#include <vector>

using namespace std;

This following is the compile and run:

$ g++ -Wall words.cpp 
words.cpp: In function ‘int main()’:
words.cpp:40:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
$ ./a.out
Enter the complete search text, followed by end-of-file: aa bb cc [CTRL-D]
Please enter your target word: aa
The target word [aa] was in the search text 1 times.

which is what I expected to see...

Edit2: For completeness: The "success rate" of using cin.clear() will depend on the implementation. A more reliable solution is to use a different way to mark the end of the stream of words in the first phase of the program. One could use a single "." or "!" or some other thing that isn't supposed to be in a "word" - or something longer, such as "&&@&&", but that makes it hard to type and remember when one is 15 pages into the input.



回答2:

When execution leaves the loop

while (cin >> x){
    searchText.push_back(x);
}

it does so because the "testing" of cin has returned false, in other words, failbit and/or badbit has been set on the stream. When that is the case, any further attempt to read from the stream will fail, i.e. targetWord will be left empty.

To make the stream usable again, you have to reset the error flags by calling cin.clear();



回答3:

It would be somewhat helpful if we knew the type of x in the first loop, but basically: you read all of the available input, then try to read some more, and you're surprised that it's failing. The contrary would surprise me.

The real question is: what are you trying to do? Basically, what is the type of x, and—I'm assuming that you're supposing that cin is an interactive device because of the prompt—how do you determine that the first input has finished? If the first loop ends because of "end of file" (user entered control-D under Unix, or control-Z under Windows), then there's no way you can reliably expect to read more. Resetting the error status with cin.clear() might work; it will cause the istream to try to read more from the streambuf. But it might not; there are any number of layers below the istream which, for whatever reason, may have memorized the end of file. So you'll have to find some different way of recognizing the end.

Just guessing from the names of the variables: if you're trying to read a list of words, I'd use std::getline, with an empty line for the end of the list. So the first loop would become:

while ( std::getline( std::cin, x ) && x != "" ) {
    searchText.push_back( x );
}
if ( ! std::cin ) {
    //  Something really bad has happened...
}

Alternatively, you might want to break up the line on white space, to allow more than one word per line (and to ignore any extra white space in the line:

std::string line;
while ( std::getline( std::cin, x ) && x != "" ) {
    std::istringstream l( line );
    while ( l >> x ) {
        searchText.push_back( x );
    }
}
if ( ! std::cin ) //  ...

Even if x has some other type, you might want to consider something along these lines.



回答4:

I used cin.clear() and on my mac set-up it did not seem to clear the EOF but on a ubuntu set-up it did clear the stream

Apple:

(Canopy 32bit) joes-imac:chap3 joe$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)

Ubuntu:

joe@joe-HPlaptop:~$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.

I am happy to accept it is just compiler differences and finish/ close the issue (was a silly little one really!)

Thanks for all the help though (my first stackoverflow question actually!)



标签: c++