Hi, I wrote this code for C++ Primer Plus, but I don't really get why it doesn't work.

#include <iostream>
#include <cctype>

using namespace std;

int main()
{
    char ch;
    string str;
    int vowels = 0;
    int consonants = 0;
    int others = 0;
    cout << "Enter words (q to quit):" << endl;
    do
    {
        cin >> str;
        ch = str[0];
        if(isalpha(ch))
        {
            switch(ch)
            {
                case 'a':vowels++;
                    break;
                case 'e':vowels++;
                    break;
                case 'i':vowels++;
                    break;
                case 'o':vowels++;
                    break;
                case 'u':vowels++;
                    break;
                default:consonants++;
                    break;
            }
        }

        else
            others++;


    } while(ch != 'q');

    cout << vowels << " words beginning with vowels" << endl;
    cout << consonants << " words beginning with consontants" << endl;
    cout << others << " others" << endl;

    return 0;
}

When I change the ch to str in the while condition, it works pretty well. I found an alternative solution to the problem, but I am not really worried about the solution, but rather why my solution does not work. Nothing seems wrong with it and it compiles fine, but it doesn't seem to correctly count the number of vowels/consonants in the string.

You only look at the first character of each word.

Sorry, forget to mention that I was counting the consonants, vowels, and others of the character in the beginning of each string.

One thing sticks out, it's not a huge deal, but what if your user enters a word that starts with "q"? Since ch is equal to the first letter in the string it would quit on them even if they didn't actually want to.

Also, you're only checking for lower case vowels. Uppercase vowels are different characters and thus would not register. The easiest way to solve this would be to use transform to make all the letters lowercase.

transform(object.begin(), //specifies the beginning of the transformation
          object.end(), //specifies the end of the transformation
          tolower); //Specifies the transformation, in this case, all contents to lower case.

Of course, since you're only grabbing the first character you could just lowercase the first character:

transform(object.begin(), object.begin(), //Only one parameter within that range
           tolower);

Also, you're grabbing the "q" at the end when the user quits, thus adding another consonant. Add an "if" statement within the loop to ensure that your program doesn't count the quit procedure.


Other than that, it should work. I can't see anything else wrong with it, at least.

Not sure what the problem is here, seems to run fine for me..

vance@Vance-ubuntu:~/programming/stuf$ ./a.out
Enter words (q to quit):
This is a test of your first-letter type counting program q
3 words beginning with vowels
8 words beginning with consontants
0 others

You are counting the control "q" as a word that begins with a consonant... maybe test for '\n' instead.

Hm maybe it's just my compiler. I'm using Code::Blocks and I typed a line of input only to see that it gives me 2 fewer consonants and vowels and 1 less "others" than it was supposed to. Thank you everyone for all your answers!

Hm maybe it's just my compiler. I'm using Code::Blocks and I typed a line of input only to see that it gives me 2 fewer consonants and vowels and 1 less "others" than it was supposed to. Thank you everyone for all your answers!

Code Blocks isn't a compiler, and I doubt it's your compiler anyways.

Show an example of this behavior. Show the input, and the output.

transform(object.begin(), object.begin(), //Only one parameter within that range
           tolower);

This example doesn't work, for two reasons:

1) If you pass object.begin() twice as a range, what you get is the empty string immediately before the first character (if any) in object.

2) You can't actually pass tolower as an argument to a library function because tolower itself is overloaded.

One way to accomplish the same end that does work, and (in my opinion) is easier to understand:

if (!object.empty())
    object[0] = tolower(object[0]);
commented: Thanks for pointing that out. +1

1) If you pass object.begin() twice as a range, what you get is the empty string immediately before the first character (if any) in object.

You're right, it should be:

object.begin(), object.begin() +1

2) You can't actually pass tolower as an argument to a library function because tolower itself is overloaded.

Some compilers seem to have a problem with this, some don't. I've been able to use plain tolower before, but sometimes you have to specify which function:

object.begin(), object.begin() +1, ::tolower

Also, I forgot to specify where to place the transformation:

transform(object.begin(), //Beginning of range to transform
          object.begin() + 1, //End of range to transform
          object.begin(), //Where to place the resulting transformation
          ::tolower); //transforming to lowercase

One way to accomplish the same end that does work, and (in my opinion) is easier to understand:

if (!object.empty())
    object[0] = tolower(object[0]);

True, but its functionality doesn't reach as far.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.