Question

I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.

#include <iostream>
using namespace std;

int main()
{
    char Ch = ' ';
    int WordCount = 0;
    int LetterCount = 0;

    cout << "(Reading file...)" << endl;

    while (cin.get(Ch))
    {
        if ((Ch == '\n') || (Ch == ' '))
        {
            ++WordCount;
            LetterCount = 0;
        }
        else
            ++LetterCount;
    }

    cout << "Number of words => " << WordCount << endl;

    return 0;
}
Was it helpful?

Solution

while (cin >> Ch)
{   // we get in here if, and only if, the >> was successful
    if ((Ch == '\n') || (Ch == ' '))
    {
        ++WordCount;
        LetterCount = 0;
    }
    else
        ++LetterCount;
}

That's the safe, and common, way to rewrite your code safely and with minimal changes.

(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)

The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.

string word;
while(cin >> word) {
   ++word_count;
}

There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:

"did the last extraction operation succeed or fail?"

This is not the same as:

"are we now at EOF?"

After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.

TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.

OTHER TIPS

The Counting

The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.

Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?

You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.

Loop Termination

I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.

Idiom

The standard idiom for reading from a stream is

char c = 0;
while( cin >> c )
   process(c);

I do not deviate from it without serious reason.

you input file is

this is fun!{EOF}

two spaces make WordCount increase to 2 and then EOF, exit loop! if you add a new line, you input file is

this is fun!\n{EOF}

I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.

cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.

In your case, the correct way to bail out of the loop is:

while (cin.good()) {
  char Ch = cin.get();
  if (cin.good()) {
    // do something with Ch
  }
}

That said, there are probably better ways to do what you're trying to do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top