Medium · string state

Count the Words

The first problem where you have to remember something about the previous character to decide what the current one means. That's a state machine, and it's everywhere.

At a glanceA word is any run of non-space characters, so count the transitions from space to non-space — read with getline, because cin >> stops at the first space, and repeated spaces must not create empty words.

Problem

Input: A single line of text, at most 200 characters. It may contain letters, punctuation and spaces, including leading and trailing spaces, and several spaces in a row.

Output: The number of words, where a word is any run of non-space characters.

Samples:

InputOutput
hello world2
a b c 3
0

Read it with cin.getline(s, size), not cin >> s. The latter stops at the first space and would give you one word for every input.

Your solution

main.cpp — your solution
Custom input for "Run my input"

Judging runs in your browser against hidden tests. A runaway loop is cut off after 3 seconds — still, make sure every loop has an exit. Your code is saved in this browser as you type.

Stuck? Hints

Hint 1 — Don't count words — count word <em>starts</em>

Walking character by character, you can't see a whole word. But you can spot the exact moment one begins: the current character is not a space, and the previous one was. Every word start is one word.

Hint 2 — Turn "previous was a space" into a variable

bool inWord = false; — am I currently inside a word? On a space, set it to false. On anything else, if it was false you just found a new word: increment the counter and set it to true. That single flag handles leading spaces, trailing spaces and runs of ten spaces, all at once.

Hint 3 — The tempting wrong answer

Count the spaces and add one. It works on hello world and fails on everything with a leading space, a trailing space, or two spaces in a row — which is most real text. This is the classic example of a shortcut that encodes an assumption about the input.

Solution (try it first!)
#include <iostream>
using namespace std;

int main() {
    char s[205];
    cin.getline(s, 205);
    int count = 0;
    bool inWord = false;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') {
            inWord = false;
        } else if (!inWord) {
            inWord = true;
            count++;
        }
    }
    cout << count << endl;
    return 0;
}

Swap s[i] == ' ' for !isalpha(s[i]) and you have a word counter that ignores punctuation. Swap it for a check against a list of separators and you have a CSV parser. The pattern — one boolean describing where I am, updated as I scan — is how compilers tokenize, how text editors highlight, how HTTP parsers find header boundaries. Next: make an array reorder itself in Bubble Sort.

Deep dive

Why this works

Scanning character by character you never see a whole word, but you can catch the exact instant one starts: this character is not a space and the previous one was. One boolean is enough.

The cost

O(length), plus one bool. "Count the spaces and add one" is cheaper to write and wrong on leading spaces, trailing spaces and double spaces — you paid for that shortcut with correctness.

Where it goes wrong

  • Reading with cin >> s stops at the first space, so every input yields one word.
  • Counting spaces and adding one fails on all three cases at once: leading space, trailing space, two spaces in a row.

Next step

Same state-machine skeleton, different separator, and you have a CSV parser. Now let an array reorder itself: Bubble Sort.

Two things to remember

  • Don't count words — count where words begin.
  • One boolean describing where you are, updated as you scan: that's a state machine.
🐞 This version fails — open it and try

Counts spaces and adds one — fails on leading, trailing and double spaces

#include <iostream>
using namespace std;

int main() {
    char s[205];
    cin.getline(s, 205);
    int count = 1;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') count++;
    }
    cout << count << endl;
    return 0;
}