C++/C++

Advertisement


Question
Hello, I am having a problem and its driving me crazy because I can't figure it out. I am new to C++. I'm hoping you can help me. Here is my code. It works so far, but I want to prompt the user to input how many times they want the program to run and what they want it to count up to. Every time I throw a variable in and try to change it, it never works. Can you point me in the right direction? Or maybe I did the entire program wrong? I'm not sure.

int main(void)
{
  int countUp=0, countDown=9, displayLoop;
  for(displayLoop=1; displayLoop<=3; ++displayLoop) // Runs the entire program 3 times
  {
  cout<<"
THIS IS for LOOP "<<displayLoop<<"
"<<endl;
  while(countUp<=9) // loops while countUp is <=10. This is the outer loop.
        {
           cout << countUp <<"   -->  ";
              do
              {
                 cout << " " << countDown;
                 --countDown;
              }
              while(countDown!=-1);
// loops while countDown is NOT = 0. This is the inner loop.

           cout << "
";
           countDown=9;
           ++countUp;
        }

     countUp=0;
     countDown=9;
  }
  cout<<"

"<<endl;
  system("pause");
  return (0);
}


Answer
Error Fixes:
------------

Apologies, I just realised I got the behaviour of the stream states messed up.

I have revised this information and the code fragment for checking the state of the std::cin stream.

--------------

OK so how about I point you in the right direction and show you how to do this for the first value you require from the user - how many times to they want the whole thing to execute and then let you have a go at doing the other one?

OK. First you will require somewhere to place the entered value:

   unsigned int numberOfRuns(0);

Next you need a prompt. No rocket science there, just write out a string of text to the console:

   cout << "How may time do you want to repeat this program (1 to 25)? ";
   
Then you need to read into this variable:

   cin >> numberOfRuns;

Now as this is input from the user it cannot be trusted so we need to check that all went OK:

   if ( numberOfRuns<1 || numberOfRuns>25 )
   {
       // go back an try again.
   }

OK so that "go back an try again" would imply that a loop would be useful rather than just an if:

   while ( numberOfRuns<1 || numberOfRuns>25 )
   {
       cout << "How may times do you want to repeat this program (1 to 25)? ";
       cin >> numberOfRuns;
   }

In fact any time we read from or write to a stream we should check that the operation was successful, although this can of course get tedious for writing to the console. We can check a stream is generally OK by testing it directly:(I am assuming ISO standard C++ IOStream behaviour here), e.g.:

   if ( ! cin )   
   {
       cerr << "Input stream failure." << endl;
       return 1;
   }

Or for specific states by calling one of several member functions:

   cin.eof()   -   returns true if end of file reached
   cin.fail()  -   returns true if there was a fatal, bad, error or soft failure (usually a formatting error)
   cin.bad()   -   returns true if there was a fatal error
   cin.good()  -   returns true if not bad, fail or eof

Testing a stream directly is equivalent to not stream.fail():

   if ( cin ) // true if std::cin is not in an bad or fail state ( !cin.fail() )
   
And using the ! operator on a stream is equivalent to stream.fail():

   if ( ! cin ) // true if std::cin in a bad or fail state  ( cin.fail() )

I am using cin above but these apply to any C++ iostream - although failures due to formatting errors are of course pretty much an input stream thing (e.g. code is expecting a character sequence that represents an integer and the user enters "what?").

Oh, and in ISO standard C++ virtually all standard library names are in the std namespace and this includes cin, cerr and cout, so more correctly they are std::cin and std::cerr and std::cout. I Presume you have a

   using namespace std;

directive in your code somewhere before the definition of main.

In this case you could check that cin is OK each time around the loop. I would suggest that for reading from the console all errors except fail are fatal and cause the program to terminate:

   while ( numberOfRuns<1 || numberOfRuns>25 )
   {
       cout << "How may times do you want to repeat this program (1 to 25)? ";
       cin >> numberOfRuns;
       
       if ( ! cin.good() )
       {
           if ( cin.bad() || cin.eof() )
           {
               cerr << "Unrecoverable error: Input stream bad or end of file reached." << endl;
               return 1;
           }
           else
           {
               numberOfRuns = 0;
           }
       }
   }

However this code has a couple of problems. First if cin fails then the failed state for cin will remain and nothing will be read - so we end up whizzing around the loop outputting the user prompt. We can clear all stream state flags using the clear() member function:

   cin.clear();
   
Next we find that not all the input will have been read from cin, and so will be re-read each time causing failures again - and still we loop endlessly - doh! To fix this problem we have to eat up the un read trash input, which we can do with the ignore() member function. To do this we give it the number of characters to ignore at maximum and the final character to ignore if found before the number of characters to ignore has been reached. So we can give it a large number of characters to ignore and specify '\n' (newline) as the up to and including character:

   cin.ignore(100000, '\n');

Of course what we really would like to say is ignore all characters up to and including the next newline character and for this we have to specify the largest int value - which is given by std::numeric_limits<int>::max() - or just numeric_limits<int>::max() if you have a:

   using namespace std;

directive in effect. You need to include the <limits> header to use std::numeric_limits:

   #include <limits>  // place at start of program with #include <iostream>

This makes the call to cin.ingore() look like so:

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

OK so putting all this together should get you a value between 1 and 25 (which I chose arbitrarily). In fact maybe these values should be named constants rather than magic numbers. If so then the whole of the code to get the input value so far would look something like so:

   unsigned int const MinimumNumberOfRuns(1);
   unsigned int const MaximumNumberOfRuns(25);
   
   unsigned int numberOfRuns(0);

   while ( numberOfRuns<MinimumNumberOfRuns || numberOfRuns>MaximumNumberOfRuns )
   {
       cout << "How may times do you want to repeat this program ("
            << MinimumNumberOfRuns << " to "
            << MaximumNumberOfRuns << ")? ";
       cin >> numberOfRuns;
       
       if ( ! cin.good() )
       {
           if ( cin.bad() || cin.eof() )
           {
               cerr << "Unrecoverable error: Input stream bad or end of file reached." << endl;
               return 1;
           }
           else
           {
               numberOfRuns = 0;
           }
       }
   }

All that remains is to use the numberOfRuns value so obtained from the user:

   for(displayLoop=1; displayLoop<=numberOfRuns; ++displayLoop) // Runs the entire program numberOfRuns times

That is replace the literal value of 3 with the variable numberOfRuns in the for loop termination condition.

I hope this helps and is enough detail to allow you to ask for, obtain, validate and use the other value you wanted from the user.

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

©2012 About.com, a part of The New York Times Company. All rights reserved.