Need to understand the logic of word count

Hi Tech gurus,

I am very new to c++ , I have started learning c++ using "thinking in c++", and I am practicing the questions. the 3rd question of the 1st chapter is Create a program that opens a file and counts the whitespace-separated words in that file. I could not get the right solution so googled it and found the below solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  #include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
  ifstream f("helloworld.cpp");
  int nwords=0;
  string word;

  while (f >> word)
    ++nwords;

  cout << "Number of words = " << nwords << endl;
}


what I do not understand is this while (f >> word) , can someone please explain the logic.
operator>> extracts series of non-whitespace characters delimited by whitespace characters.
If it cannot extract next series of characters, it sets failbit in stream it extracts from. It also returns reference to said stream. That sream has implicit conversion operator which converts stram to bool. If everythin is fine with stream (no errors) it converts to true and loop body executer. If not (end of stream) — loop stops.
As "series of non-whitespace characters delimited by whitespace characters" can be defined as "words", it could be said that it counts words.
Example of file content and extracted words:
1
2
3
4
5
6
7
Hello world!
Glad to see you, world!
Hello
world!
Glad
to
see
you,
world!
Plus:
leading whitespaces are discarded before formatted input operation

We have just successfully read a word. The next character in the stream is thus whitespace. (State A)

The next read operation starts by discarding whitespace until a non-whitespace character is found. We "skip whitespace", skipws. Then the actual "read a word" that stops on next whitespace. We are back at state A.

It is possible to explicitly include the leading whitespace(s) into the word.
Thanks all for the reply...
What i understood is operator >> doesn't recognize whitespace and skips it so we read one by one word, right?

so if we have something like
1
2
3
4
string s;
cout << "enter a string"<< endl;
cin >> s; // and we enter a string like "xyx 8 abc"
cout << s; // it should only print xyz , right? 
Yes. (It should be easy for you to test that. yourself.)
Thanks for the reply.
I have written a simple code to understand the same , but now I am trying to modify a little to get the input from user as a string and write the words in the file using the same logic. but it gives me the error
"in function int main
no match for 'operator >>' in 's>> out'"
Please tell me why ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
#include<string>
#include<fstream>

using namespace std;

int main()
{
    string s;
    ofstream out("writeme.cpp");
    cout << "enter " << endl;
    cin >> s;
   // cout << "u hv entered " << s << endl;
    while ( s >> out )
    {
          cout << out << endl;
          }
    system("pause");
    return 0;
}
s is a string. Which does not support steam operations. And you are trying to use stream as right-hand operand to the extraction operator which is not possible too.
You can use stringstreams for that, but:
1) You won't even need loop because there would always be only one word (you can circumvent this by using getline())
2) cout << out << endl; Is clearly wrong. What are you trying to do here?
sorry for the mistake.. i wanted to see the words, but we can't see like this.
SO you want:
1) Get a line which consist of several words from user.
2) Output those words, each on its own line, to file.
3) Output those words on screen too.
Do I understand you correctly?
Sorry for the mistake , i was trying to see all the words, but we can't do that. thanks...
You could have put
1
2
3
4
    while (cin >> s)
    {
        out << s << endl;
    }
that will save all the words to the file.

But it may need some way to exit from the loop, such as testing for a particular word:
1
2
3
4
    while (cin >> s && word!="quit")
    {
        out << s << endl;
    }

There is always the EOF (end-of-file) to end with. Possibly:
You can simulate EOF with CTRL+D (for *nix) or CTRL+Z (for Windows)


It's the EOF that the OP example does use:
1
2
3
while ( f >> word ) {
  ++nwords;
}

Naturally, the condition can test multiple things, as in:
1
2
3
while ( cin >> word && "quit" != word ) {
  ++nwords;
}

Now, either the read succeeds and 'word' can be tested, or read failed for whatever reason (including reaching the EOF).

One can go a step further and test the success of the file writes too:
1
2
3
while ( cin >> word && "quit" != word && out << word << '\n' ) {
  ++nwords;
}

Obviously, the body of the loop could instead/in addition to counting to write the words to cout/cerr/clog as well.
@ MiiNiPaa

Yes :)
@ all
I have tried the below code as I was suggested but even after pressing enter the screen waits for input , i mean I can see the cursor blinking.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include<iostream>
#include<fstream>
#include<string>

using namespace std;
int main ()
{
    ifstream in ("writeme.cpp");
    ofstream out ("writeme.cpp");
    string s;
    string x;
    cout << "enter the string" << endl;
    while(cin >> s )
    {
           out << s << endl ;
    }
    while (in >> x)
    {
          cout << x;
    }
    system("pause");
    return 0;
}
You need to send end of stream signal or go for keskiverto approach and test for sentiel word input.

Or change your code to work with getline() and stringstream:

Also: you are opening same file in two streams. As all IO is buffered, it might not work as you expect. Either close output file before opening it for input, use generic i/o stream or do some synchronization between streams.

Assuming you really want first save words for file and then read them from it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>

int main ()
{
    std::string s;
    cout << "enter the string" << endl;
    std::getline(std::cin, s);
    std::istringstream input(s);
    std::ofstream out("writeme.cpp");
    while(input >> s) {
           out << s << '\n';
    }
    out.close();
    std::ifstream in("writeme.cpp");
    std::cout << in.rdbuf();
}
Last edited on
@Miinipa
What is understood keskiverto said that while(cin >> s ) checks eof, kindly correct me if I understood wrong.
keskiverto said that while(cin >> s ) checks eof
Yes it does. But eof means that there will no future input in this stream ever. When you enter something in console you will never reach eof normally. You have to manually send EOF to the console which will send it to the stream.
In Unix it is Ctrl+D
In Windows it is Ctrl+Z on new line
Last edited on
@Miinipa

but i am taking the input from console. so how can i check my end of string,, i googled but didn't get much.
I gave you an example how you could read one line: Use getline() to read single line and then use stringstream to parse it (lines 10-15 in my post) http://www.cplusplus.com/forum/beginner/134652/#msg719773 .

Also I told you how to manually send EOF to console to read several lines until no further input is needed.

keskiverto shows example how to take words until sentiel word is entered.

If you want other behavior, describe it and we will help. If you have some trouble with understanding existing example, point it out so we know what do you want.
thanks a lot... i made it work now... i have understood also the logic :)
Topic archived. No new replies allowed.