C++/C++
Expert: Ralph McArdell - 10/17/2010
QuestionHello, 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);
}
AnswerError 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.