2

I am trying to count the number of words in a file, I know this question has been asked but I have tried some implementations I have seen but I keep getting an error.

The line in the file I am reading is "Super Chill" but when I run the code I get a count 3, where >> gets Super the first time and then Chill twice. I have a couple questions regarding this method:

1) what does While(in) look for? How does it know when to stop?

2) Why is "Chill" getting stored twice with >>?

Here is the code

int countWords(std::istream& in){ // line in file is -> Super Chill

    int count = 0;
    std::string word;
    while (in) {
        in >> word;
        if (word != "") {
            count+= 1;
        }
    }

    return count;
}
user2076774
  • 285
  • 1
  • 6
  • 21

2 Answers2

5

while (in) checks if no error has occurred. It's the same as writing while (!in.fail())

After you call in >> word and get the first "Chill", while (in) still is true, until the next call to in >> word. When you hit in >> word again it fails because it's at the end of the file and doesn't write anything to word, but the word variable still has "Chill" in it from the last time, so you count it a second time. Then the while (in) finally fails on the next iteration.

Calling while (in >> word) { ++count; } works because in >> word is actually the function in.operator>>(word) which happens to return an istream&, and an istream has an operator bool method which allows you to use it in a condition instead of writing !in.fail(). Sort of roundabout, I know. Point is, it calls in >> word, then checks if (in) and if it passes then calls ++count; and iterates again. Versus your original technique which counted the previous word even if in >> word failed.

To make this clearer, it might help to know that changing your original code's if statement to if (in) would have also worked, but would be sort of bad code.

As a final conclusion, the entire function could be written as:

int countWords(std::istream& in) {
    int count = 0;
    for (std::string word; in >> word; ++count) {}
    return count;
}
David
  • 25,830
  • 16
  • 80
  • 130
  • So what exactly does >> do? I know it grabs a word but does it move some reference along the line, what constitutes a "failure" in my original solution where >> didn't work the third time and while(in) failed? – user2076774 Dec 09 '15 at 23:22
1

I see you've already gotten one solution to the problem you posted. You might want to consider another possibility though:

int countWords(std::istream& in){  
    return std::distance(std::istream_iterator<std::string>(in),
                         std::istream_iterator<std::string>());
}

This doesn't actually eliminate the loop, but it hides it inside of std::distance where it's pretty difficult to mess things up.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035