element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Code Exchange
  • Technologies
  • More
Code Exchange
Blog C++ Tutorial - While Loops
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Code Exchange to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: oneleggedredcow
  • Date Created: 30 Jan 2013 3:10 AM Date Created
  • Views 14665 views
  • Likes 1 like
  • Comments 3 comments
  • code_exchange
  • Code Exchange
  • programming
  • raspberry_pi
  • code
  • rpi
  • c++
  • learnc++
Related
Recommended

C++ Tutorial - While Loops

oneleggedredcow
oneleggedredcow
30 Jan 2013

Introduction

In the previous tutorial, we learned how to make our code more concise and flexible by using for loops. In this tutorial, we will learn about another kind of loop: the while loop.  We will use this loop to make our code more robust by screening out bad user input.

Code

In our guess my secret number game from the previous tutorials, what we really want is the user to input a number between 1 and 10.  Anything outside of that range, should be rejected as an invalid guess. So, here’s how to validate the user’s input:

 

int guess = 0;

while (guess < 1 || guess > 10)

{

cout << “Guess a number between 1 and 10? ” << endl;

cin >> guess;

}

 

First, this code declares a new variable called guess.  Then the while loop checks to see whether the loop should be executed.  This is like the second (or middle) part of the for loop from last time.  The double vertical line (||) means or, meaning that if the left hand side or the right hand side are true, then the whole expressions should be true.  The left side (guess < 1) is true, since zero is less than one, while the right hand side (guess > 10) is false, so the whole expression is true and the loop is executed.  The user is then prompted to enter a guess and after they enter a guess, the loop check is evaluated again.  If the user inputs a number between 1 and 10, the loop stops.  If not, the loop keeps going until the user inputs a number between 1 and 10.

 

Validating user input is extremely important!  Probably the largest source of bugs in software comes from a naïve assumption that the user will know what they should input and that they won’t deviate from that (intentionally or not).  If you have ever heard of SQL injection hacks, they are basically caused because the programmer didn’t properly validate what the user typed in.

You might be thinking, wait, can’t a for loop do that as well?  The answer is yes.  For loops and while loops can always be converted from one to the other.  Here’s what the previous code would look like as a for loop:

 

for (int guess = 0; guess < 1 || guess > 10; ; )

{

cout << “Guess a number between 1 and 10?” << endl;

cin >> guess;

}

 

The only strange part of this loop is the third parameter in the for loop.  This is the code that is executed after each loop executed and before the loop continuation check is done.  (This is typically where the variable declared and set to a value in the first part of the loop is incremented.)  Since we don’t need to modify the guess variable, we just leave it blank.

 

So, how do you know which loop to use?  Whenever you are looping through a list of numbers use a for loop.  For example, if you wanted to loop through all of the numbers from 1 to 10 or if you wanted to loop through all of the even numbers from 50 to 100.  Whenever you want to loop until something happens, use a while loop.  For example, to keep looping until the user types in valid input.

There is another loop called the do while loop.  This loop is very similar to the while loop, but it doesn’t do the loop continuation check before the loop executes, only after each loop.  So, here is what it would look like:

 

int guess = 0;

do

{

cout << “Guess a number between 1 and 10?” << endl;

cin >> guess;

} while (guess < 1 || guess > 10)

 

So, unlike the while loop, which does a check before the loop starts, the do while loop executes the loop once and then checks to see if the input is valid.

 

The do while loop is very uncommon.  I think the reason that it is uncommon is that it can be easily replaced by a while loop and the while loop is slightly more flexible.  It’s more flexible because the while loop doesn’t have to be executed, whereas the do while has to be executed at least once.  So, in places where a do while might be used, usually a while loop is used along with data that is set to have the loop executed at least once, like the example above.  The guess variable is set to an invalid guess (zero), so that the loop is executed.  This is the preferred way to do things, so that in the future if we change the program in a way that we don’t have to prompt the user for input, then no modifications are required.  One example would be if we changed the program to take guesses as an optional command line argument.  In this case, we wouldn’t want to prompt the user since they already told us their guess.

 

Handling the user typing in random letters is more difficult to handle.  In order to do that, we need change the loop to look something like this:

 

int guess = 0;

while (guess < 1 || guess > 10)

{

cout << "Guess a number between 1 and 10?" << endl;

cin >> guess;

 

if (cin.gcount() != 1)

{

cin.clear();

cin.ignore(numeric_limits<int>::max(), "\n");

}

}

 

If the user enters in something other than a number, then gcount will not be equal to one.  When this happens, then we want to clear the errors from cin and ignore all characters in the input stream.  This will make it so that letters are ignored and the user will be forced to type in a number.

 

Attached below is the final version of the guess my number game, this time with a while loop to validate the user’s input.

Summary

In this tutorial, we learned how to make our code more robust by using a while loop to verify that the guess that the user typed in was valid.

 

In the next tutorial, we will be going over functions.  Functions are a great way to reuse code and to abstract away solutions to common problems.

 

If you have any questions or comments about what was covered here, post them to the comments.  I watch them closely and will respond and try to help you out.

Tutorial Index

01 - Hello Raspberry Pi

02 - Reading User Input

03 - If Statement

04 - For Loops

05 - While Loops

06 - Functions

07 - Data Types

08 - Arrays

09 - Structures

10 - Classes

11 - Pointers

12 - Dynamic Arrays

13 - Linked List

14 - Linked List Operations

15 - STL List/Vector

16 - Templates

17 - Inheritance

18 - File I/O

19 - Strings

20 - Constants

21 - Hash Tables

Attachments:
05_GuessMyNumber.cpp.zip
  • Sign in to reply

Top Comments

  • shabaz
    shabaz over 8 years ago in reply to mjahpi +1
    Hi Mark, Shaun has not logged on for a while, so if I can reply, my only comment is that there are more ways than one to kill a cat, and (personally) I would have used a different method, despite this…
Parents
  • mjahpi
    mjahpi over 8 years ago

    Hello;  I have a concern with your use of "cin.gcount()".  I have made a few modifications to your code to illustrate my concern.  For consistency and testing , I set the secret number to always be five (5).  I have also added a few "cout <<" statements to ensure my guess, also always five (5), is correctly assigned by your statement "cin >> guess;" and to examine  the value of "cin.gcount()".  it is examined immediately after your "cin >> guess;" statement.  here a portion of the modified code.  Note: my changes are left justified for clarity. 

     

    int main()

    {

          // Randomly generate a secret number

         srand((unsigned int) time(NULL));

         int num = (rand() % 10) + 1;

         int num_guesses = 3;

     

         // Print out number first (used for debugging purposes, no cheating!)

    num = 5;

    cout << "Secret num is : " << num << endl;

     

           // Game intro

          cout << "I'm thinking of a secret number (1 - 10), can you guess it?" << endl;

     

         for (int i = 0; i < num_guesses; i++)

         {

              int guess = 0;

     

              // Read in guess

              while (guess < 1 || guess > 10)

              {

                   cout << "Guess a number between 1 and 10? ";

                   cin >> guess;

    cout << "cin.gcount is : " << cin.gcount() << endl;

    cout << "Guess is  : " << guess << endl;

                  if(cin.gcount() != 1)

                  {

    cout << "in here (!= 1) , cin.gcount is : " << cin.gcount() << endl;

                        cin.clear();

                        cin.ignore(numeric_limits<int>::max(), '\n');

                  }

    CONTINUES UNCHANGED

     

    My output: 

     

    Secret num is : 5

    I'm thinking of a secret number (1 - 10), can you guess it?

    Guess a number between 1 and 10? 5   Note:  the 5 after the question mark is my input

    cin.gcount is : 0

    Guess is  : 5

    in here (!= 1) , cin.gcount is : 0

    Correct, my secret number was 5

     

    You can see that despite the correct answer provided "cin.gcount() returns "0" rather than "1" as suggested in your code. 

    Comments? 

    Regards, Mark Hache

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • mjahpi
    mjahpi over 8 years ago

    Hello;  I have a concern with your use of "cin.gcount()".  I have made a few modifications to your code to illustrate my concern.  For consistency and testing , I set the secret number to always be five (5).  I have also added a few "cout <<" statements to ensure my guess, also always five (5), is correctly assigned by your statement "cin >> guess;" and to examine  the value of "cin.gcount()".  it is examined immediately after your "cin >> guess;" statement.  here a portion of the modified code.  Note: my changes are left justified for clarity. 

     

    int main()

    {

          // Randomly generate a secret number

         srand((unsigned int) time(NULL));

         int num = (rand() % 10) + 1;

         int num_guesses = 3;

     

         // Print out number first (used for debugging purposes, no cheating!)

    num = 5;

    cout << "Secret num is : " << num << endl;

     

           // Game intro

          cout << "I'm thinking of a secret number (1 - 10), can you guess it?" << endl;

     

         for (int i = 0; i < num_guesses; i++)

         {

              int guess = 0;

     

              // Read in guess

              while (guess < 1 || guess > 10)

              {

                   cout << "Guess a number between 1 and 10? ";

                   cin >> guess;

    cout << "cin.gcount is : " << cin.gcount() << endl;

    cout << "Guess is  : " << guess << endl;

                  if(cin.gcount() != 1)

                  {

    cout << "in here (!= 1) , cin.gcount is : " << cin.gcount() << endl;

                        cin.clear();

                        cin.ignore(numeric_limits<int>::max(), '\n');

                  }

    CONTINUES UNCHANGED

     

    My output: 

     

    Secret num is : 5

    I'm thinking of a secret number (1 - 10), can you guess it?

    Guess a number between 1 and 10? 5   Note:  the 5 after the question mark is my input

    cin.gcount is : 0

    Guess is  : 5

    in here (!= 1) , cin.gcount is : 0

    Correct, my secret number was 5

     

    You can see that despite the correct answer provided "cin.gcount() returns "0" rather than "1" as suggested in your code. 

    Comments? 

    Regards, Mark Hache

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • shabaz
    shabaz over 8 years ago in reply to mjahpi

    Hi Mark,

     

    Shaun has not logged on for a while, so if I can reply, my only comment is that there are more ways than one to kill a cat, and (personally) I would have used a different method, despite this being an excellent tutorial series. I have not used gcount nor come across it in any code I've written or observed. It might not be a popular thing for all (people tend to reuse what works for them, because it is often lower-risk to reuse code that you know you've already tested and confirmed working, and I happen to have not used gcount).

     

    As a suggestion, I think it is worthwhile to first check out Shaun's tutorial section where he discusses C++ strings, and then google around that area. There are dozens of methods you could apply to a C++ string to do all sorts of validation-type features, such as check for string length, convert to integer, check for specific characters present or not present, and so on.

    There are also libraries, it really depends on how much validation, parsing etc you want to do.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • watchman
    watchman over 7 years ago in reply to mjahpi
    You can see that despite the correct answer provided "cin.gcount() returns "0" rather than "1" as suggested in your code.

     

    This does indeed appear to be a problem.

    What is expected is that if a number is entered gcount would return 1 due to the remaining '\n' character. However this is not how gcount works.

     

    According to http://www.cplusplus.com/reference/istream/istream/gcount/

    Return Value: The number of characters extracted by the last unformatted input operation.

     

    However, from http://www.cplusplus.com/reference/istream/istream/operator>>/

    Except where stated otherwise, calling this function does not alter the value returned by member gcount.

     

    Since this is the first call to cin and the >> operator does not alter gcount it is going to return 0 as you observed.

     

    This actually introduces a bug.

    Whilst the >> operator does not alter gcount, ignore does.

     

    Enter a number, any number (not the answer), even make it invalid (say 100). The >> operator doesn't alter gcount and the initial value of 0 is retained.

    As a consequence the if clause is true and ignore is executed. This removes the '\n' character setting gcount to 1.

    Now enter a non-numeric value. Again the >> operator doesn't alter gcount and the previous value of 1 is retained.

    As a consequence the if clause is false and the important step of flushing the stream is not executed. The program now enters a loop of continually trying to read the invalid input.

     

    A more logical approach would be to use:

     

    if(cin.fail() == true)

     

    However this leads to a double user prompt if the user enters a number followed by some text (e.g. "4teen").

    The cleanest approach is to drop the if clause entirely and just execute the clear and ignore every time to clear any error and flush the stream of any spurious characters.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube