Hello everyone,
I have a small question about the code below, I understand just about every part of it.
Except for this small snippet, could someone explain how the loop works?

while(begin != end )    //<-- I believe the stream iterator is getting input here
    words[*begin++]++;  // <-- I can see here that the string that was typed in is stored in the map words(*begin), but how is the int in the map being accessed and incremented and when the words are outputted how have they been separated? When I dereference *begin I get the whole string that was typed, but when I output them at the end of the program they have been seperated.
// A simple word counting program
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <iterator>
using std::cout;
using std::cin;
using std::endl;
using std::string;

int main() 
{
  std::map<string, int> words;           // Map to store words and word counts
  cout << "Enter some text and press Enter followed by Ctrl+Z then Enter to end:"
       << endl << endl;

  std::istream_iterator<string> begin(cin); // Stream iterator 
  std::istream_iterator<string> end;        // End stream iterator

  while(begin != end )                      // Iterate over words in the stream 
    words[*begin++]++;                      // Increment and store a word count

  // Output the words and their counts
  cout << endl << "Here are the word counts for the text you entered:" << endl;
  for(auto iter = words.begin() ; iter != words.end() ; ++iter) 
    cout << std::setw(5) << iter->second << " " << iter->first << endl;

  return 0;
}

Edited 5 Years Ago by L3gacy: n/a

First of all, the istream iterator gets initialized at the line 18, and so does the end iterator (default-constructed iterator marks the end).

Second, the while loop simply iterates until begin reaches the end of the input. That is what the (begin != end) condition verifies.

Third, the *begin++ dereferences the begin iterator, and increments it (for the next iteration of the while loop).

Fourth, the words[s] finds an entry in the map associated with the string "s" (or *begin++ in this case). The values associated to the strings are integers, because of the declaration std::map<std::string,int> meaning that the map associates integer values to string-valued keys. Now, if the entry does not exist (that string has not been seen before), then the [] operator of std::map will take care of creating a new entry for that string, and the integer value associated to it will be default-initialized (or zero-initialized) meaning that it will have value zero.

Then, the entry gets incremented. So, every time a string is seen it will be registered in the std::map that keeps count of the number of occurrences of every word.

Finally, the reason why the words get separated when you output them at the end of the program is because std::map keeps all the entries sorted by the key (the strings), so it will appear in alphabetical order when outputted. And the reason why you get the whole sentence when you just re-output the values of *begin++ is because you are just re-printing what you are reading. The way the istream iterator works is by waiting for the input buffer to be flushed (e.g. by pressing enter), then it reads one word (to which "begin" points to, only the first word), and then, every time you increment the iterator it will read the next word. If you print it out directly, you will, of course, just get an echo of the input, but it is still being split into separate words.

while(begin != end )  
    words[*begin++]++;

is the same as:

while(begin != end )    //<-- I believe the stream iterator is getting input here
 {    
    int count = words[*begin]; //get the value for the given word
    words[*begin] = count + 1; //increase the count by 1 
    ++begin; //move to next word
 }

Edited 5 Years Ago by firstPerson: n/a

This question has already been answered. Start a new discussion instead.