You are here:

C++/trouble using string class in dev c++

Advertisement


Question
hello
 i am a student from india learning c++ using the booodshed dev c++ environment. i have some trouble using the string
class in c++ while coding.
  the following is the problem statement and the code
i have written :-
 
/*  Problem Description
Write a program which does the following:
   * Takes a set of lines as input
   * Prints percentage of words containing vowels.
The input words will be in
    lower case. */

#include <iostream>
#include <string>
using namespace std;

int main() {
string s;
int vowelcount=0,wordcount=0;
while (cin >>s) {
if (0<=s.find("a")<=s.length() ||
   0<=s.find("e")<=s.length() ||
   0<=s.find("i")<=s.length() ||
   0<=s.find("o")<=s.length() ||
   0<=s.find("u")<=s.length()) vowelcount++;
wordcount++;
}
cout <<vowelcount/wordcount*100 <<" %" <<endl;
cin.get();
cin.get();
return 0;
}

the input i have given is something like:-
  hello world(now i press enter)

still i donot get the desired output i.e. 100%
i .e,. i am not able to understand how do i tell that
i am done with entering the input.

  please help me in this regard

thanking you
arun

Answer
First this sort of usage does not do what you expect:

       0<=s.find("a")<=s.length()

It does do what you expect in BCPL an ancestor of C and C++, but not in C and C++. In these languages 0<=s.find("a") is evaluated then the result (false or true or 0 or 1) is used with the second part of the expression <= s.length(). It is like so:

       (0<=s.find("a")) <= s.length()

What you need to do is break the range test into two parts:

       0 <= s.find("a")
       s.find("a") <= s.length()

Then the whole result is true only if both parts are true so join them using the logical AND operator && thus:

       0 <= s.find("a") && s.find("a") <= s.length()

As you are checking for any one of several such ranges using logical OR I suggest you wrap each range test in parenthesis:

       (0 <= s.find("a") && s.find("a") <= s.length())

Even though logical AND - && - has higher precedence than logical OR - || - I would still add parenthesis to make it plain to readers what the intent is. Also, can you always remember what order of precedence all the C++ operators have?

This leads me to another problem with your code - readability. Most people find quashing code up to make it unreadable. This may mean nothing to you, after all why should you care? In this case you should because you are asking someone else to help you with your code - me! In fact you come over as a lazy non caring sort of person from the presentation of your code. If nothing else consider that the easier it is for someone else to read and _understand_ your code the better and more accurate their advise is likely to be. In general software spends 80% of its life being maintained and only 20% being created in the first place. Maintenance implies people have to read and understand the code - very often not the same people who wrote the code and often some years later.

So some specifics: do not use this style of bracing:

int main() {
   // ...
}

Or

if ( isItTrue ) {
   // ...
}

But one of these:

if ( isItTrue )
{
   // ...
}

if ( isItTrue )
   {
   // ...
   }

if ( isItTrue )
 {
   // ...
 }

Generally functions are braced like so:

int main()
{
   // ...
}

But again you can apply one of the above styles here as well, e.g.:

int main()
   {
   // ...
   }

Always ensure code is correctly indented for the level of nesting at the time. I note that you do not indent your code much at all. Although not everyone agrees I also tend to _always_ use braces for places where compound statements are used such as the body of if, else, for, while etc.even if there is _currently_ only a single statement in the clause body. All too often you find you go back and add a second line or more and at this point you need to add the braces anyway. Further, if you cannot be bothered to indent your code then it becomes confusing to work out which code is supposed to belong to which clauses. E.g. should that second line be in the if clause above? Is that a bug or was it really supposed to be outside the if? I have had to work on just such confusing client code and gone through a similar thought process.

For example rather than:

       if (0<=s.find("a")<=s.length() ||
         0<=s.find("e")<=s.length() ||
         0<=s.find("i")<=s.length() ||
         0<=s.find("o")<=s.length() ||
         0<=s.find("u")<=s.length()) vowelcount++;

I would write:

       if ( 0<=s.find("a")<=s.length() ||
         0<=s.find("e")<=s.length() ||
         0<=s.find("i")<=s.length() ||
         0<=s.find("o")<=s.length() ||
         0<=s.find("u")<=s.length()
         )
       {
         vowelcount++;
       }

I would like to see something like the following:

int main()
{
   string s;
   int vowelcount=0,wordcount=0;
   while (cin >>s)
   {
       if ( 0<=s.find("a")<=s.length() ||
         0<=s.find("e")<=s.length() ||
         0<=s.find("i")<=s.length() ||
         0<=s.find("o")<=s.length() ||
         0<=s.find("u")<=s.length()
         )
       {
         vowelcount++;
       }

       wordcount++;
   }

   // ...
}

I will be adopting such a style for further examples.

Do not try to place too much on one line. Examples from your code are:

int vowelcount=0,wordcount=0;

and

cout <<vowelcount/wordcount*100 <<" %" <<endl; cin.get(); cin.get();

Try:

int vowelcount=0;
int wordcount=0;

cout << vowelcount/wordcount*100 <<" %" <<endl;
cin.get();
cin.get();

instead.

Another example is:

   while (cin >>s)

However, this is more a style / house coding standards sort of thing. Many people do not like to do such input in a loop or if test. In your case unless the state of cin becomes not good then the loop will continue forever. The stream operator>>() operator functions return a reference to the stream. This is convertible to a void* that is used to indicate a good or eof state or a formatting failure or fatal (bad) error. I shall return to this point later.

Now to the usage of std::string objects. If you had read the documentation on this type you would know that the std::string find functions return std::string::npos if they fail to find the requested item. This implies that the test for each vowel being present can be simplified thus:

       s.find("a") != string::npos

As any value other than std::string::npos indicates that s contains at least one 'a' character.

As you are only searching for a single character why are you passing a literal string? Why not use the search for single character form and pass a character literal?

       s.find('a') != string::npos

Better yet use find_first_of to locate the first character in s that is any one of the characters in a given string:

       s.find_first_of("aeiou") != string::npos

This last will reduce the size of the if test condition significantly.
I recommend that you find a _good_ tutorial and reference for the standard C++ library. I use "The C++ Standard Library A Tutorial and Reference" by Nicolai M. Josuttis. Online documentation for parts of the C++ standard library and some non-standard extensions can be found at http://www.sgi.com/tech/stl/, but this is probably a bit terse for your needs; the string documentation is under basic_string.

Now to the problem of termination. First let us break out the reading of input from the loop continuation condition:

while ( <whatever> )
{
   cin >> s;

// ...
}

Next you need to decide what the termination condition is. Maybe an uppercase Q (for quit) as only lowercase is valid for main input. So having decided this we can check for it as the loop termination condition:

while ( s != "Q" )
{
   cin >> s;

// ...
}

This will certainly terminate the loop when Q is entered. However you will now find that that Q is being processed just like any other input, which is not what is required. The most obvious way to prevent this is to also test after we have read a new value for s that it is not Q, so the loop now looks like so:

     while ( s != "Q" )
     {
         cin >> s;

         if ( s != "Q" )
         {
         if ( s.find_first_of("aeiou") != string::npos )
         {
         vowelcount++;
         }

         wordcount++;
         }
     }

Of course we can use break to break out of a loop. However whether this is good style or not and if so when it is permissible is a matter of personal taste, house standards etc. Using break we can reduce the loop to:

   while ( true )
   {
       cin >> s;

       if ( s == "Q" )
       {
         break;
       }

       if ( s.find_first_of("aeiou") != string::npos )
       {
         vowelcount++;
       }

       wordcount++;
   }

Note that some compilers will warn you that the loop condition is constant. This is because if a loop condition never changes and the loop body contains no breaks, returns, etc. then the loop body will either never be executed or be executed forever (as would be the case here without the break).

Now to the calculation of the percentages. I added the following to display the vowel and word count values just before your result display line:

   cout << "vowelcount:" << vowelcount
        << "  wordcount:" << wordcount
        << "\n";

The problem you are having, now that the logic is fixed, is that you are using the following calculation on integers:

       vowelcount/wordcount*100

Both / and * have the same precedence so / is performed first followed by *. This means that vowelcount is _integer_ divided by wordcount. If vowelcount equals wordcount then you will get a result of 1 for this division. Howecver if vowelcount is less than wordcount then the result is less than 1, which in integer arithmetic is truncated to 0. So 99 vowels divided by 100 words to you and me gives 0.99. To integer arithmetic it gives 0 as integers can _only_ represent _whole_ numbers and 0.99 is less than 1 so the result is 0.

As the result of the division leaves us with 0 or 1 the only percentages you should get are 0% or 100%. To get better results reverse the order of the operations so the multiplication is done _first_:

      100*vowelcount/wordcount

This make 100*vowelcount be performed first, the reuslt is then divided by the wordcount. So in the previous example 99 vowels are multiplied by 100 giving 9900. This is then divided by a wordcount of 100 giving 9900/100 yielding a result of 99%.

There is a lot more I could say about your code. The only other thing I will say now is that you might like to add a few prompts for the user so they know what to do and what the results mean.

Below is the final form of your program that I used. I hope you try to understand the points I make here and do not just hand it in as your own work. Note that I have had to add additional breaks in long lines - specifically the greeting and result outputs to prevent wrapping in my text editor. As with all code it should be viewed using a mono-spaced font such as Courier.

#include <iostream>
#include <string>

using namespace std;

int main()
{
   string s;
   int vowelcount=0;
   int wordcount=0;

   cout << "Calculator of percentage of entered words having"
         " vowels\n\n"
         "Enter lowercase words separated by spaces, tabs or"
         " newlines.\n"
         "Enter an uppercase Q to quit data entry and display the"
         " results.\n";

   while ( true )
   {
       cin >> s;

       if ( s == "Q" )
       {
         break;
       }

       if ( s.find_first_of("aeiou") != string::npos )
       {
         vowelcount++;
       }

       wordcount++;
   }

   cout << "Number of word entered: " << wordcount
        << ".  Number of word contaiing vowels: " << vowelcount
        << ".\nPercentage of words contaiing vowels: "
        << 100*vowelcount/wordcount << "%"
        << endl;

   cin.get();
   cin.get();
   return 0;
}

I hope this has given you food for thought and that you will be a better programmer for it and more able to complete future assignments to a very high standard. I hope you will pass on any advice you feel worthwhile to you colleagues and attempt to help them as I helped you. Helping others is a very good way to nail down your own understanding!  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.