Validating input with do while loop - c++

I am trying to minimize hardcoding numbers into my program and allowing for users to define max and min parameters along with making sure that the input is valid.
#include <iostream>
int main(){
int max, A=0;
do
{
std::cout << "What is the max?\n";
std::cin >> max;
if (std::cin.fail()) {
std::cin.clear();
std::cin.ignore();
std::cout << "not an integer, try again\n";
continue;
}
if(max < -1000){
std::cout << "That doesnt make much sense, please enter the max again.\n";
}
} while (max <A); \\HERE IS WHERE THE PROBLEM IS.
std::cout << "The max number of steps are " << max <<std::endl;
return 0;
}
If A is 0 or less, the program doesn't ask for user input again. instead the program just exits the loop.
If A is 1 or more, then then the program loops until a valid input is provided.
I would like the max number to be any int number, including negatives. This is working for positive numbers, but not for maximums that are 0 or less.

do
{
//ask for input
//input taken
} while (A>=1);
This will the code you have to use for the scenario described at the last line. One more point you just forget to assign any value to A according to your logic.
Thanks!

If A is 1 or more, then then the program loops until a valid input is provided. - You are saying exactly what the while loop needs to do. Just implement it.
} while (A >= 1); \\If A is greater than or equal to 1 then loop until valid.
std::cout << "The max number of steps are " << max <<std::endl;
return 0;
}
To answer your follow up question:
} while (A >= 1 && max <= 0); \\If A is greater than or equal to 1 then loop until valid.
std::cout << "The max number of steps are " << max <<std::endl;
return 0;
}

I would suggest writing a custom function that takes an acceptable range of min/max values as input parameters, eg:
int promptForInt(const string &prompt, int minAllowed, int maxAllowed)
{
int value;
std::cout << prompt << "\n";
do
{
if (!(std::cin >> value)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "not an integer, try again\n";
continue;
}
if ((value >= minAllowed) && (value <= maxAllowed)){
break;
}
std::cout << "not an allowed integer, enter a value between " << minAllowed << " and " << maxAllowed << ".\n";
}
while (true);
return value;
}
int main(){
int max = promptForInt("What is the max?", -1000, 1000);
std::cout << "The max number of steps are " << max << std::endl;
return 0;
}

Related

How to set a range of int value in C++

If I have an int a; and I want to set a value for this int (cin >> a;) in a range 1 < a < 1000, what is the most effective way how to type it via code? Is there a better way then if(a <=1 || a >= 1000)? Since if I would have multiple of int which I wanted to be limited by their value, I don't want to type a condition for every single one.
Checking the condition a <=1 || a >= 1000 is exactly what you'd do ๐Ÿ‘
You will want to use a loop here, though, to re-ask for input if the input is not in the correct range.
Using the if is the best way to do what you are asking for. But, if you need to handle multiple ints, you should wrap the if inside of its own function that you can call whenever needed, eg:
int askForInt(int minValue, int maxValue)
{
int value;
do {
cout << "Enter an integer (" << minValue << "-" << maxValue << "): ";
if (cin >> value) {
if (value >= minValue && value <= maxValue) break;
cout << "Value out of range! Try again." << endl;
}
else {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Bad input! Try again." << endl;
}
}
while (true);
return value;
}
...
a = askForInt(1, 1000);

Trying to validate input in C++

The idea behind this code in c++ is to calculate the sum of all the entered numbers. When the user enters 0, the program should stop. This part of the code is working as I intended, but I'd like to include a variant which recognizes that a character different than a float number has been entered, ignore it in the calculation and allow the user to continue entering float numbers. At the moment, entering anything else but a float number stops the program.
I know there's a "if (!(cin >> numb))" condition, I've tried parsing it in different places in the code, but I can't figure out how to force the program to ignore these invalid inputs. I would be very grateful for any help.
#include <iostream>
#include <stdlib.h>
using namespace std;
float numb; float sum=0;
int main()
{
cout << "This app calculates the sum of all entered numbers." << endl;
cout << "To stop the program, enter 0." << endl << endl;
cout << "Enter the first number: ";
cin >> numb;
while(true)
{
sum += numb;
if (numb!=0)
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Enter another number: ";
cin >> numb;
}
else
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Entered 0." << endl;
cout << "Press Enter to terminate the app." << endl;
exit(0);
}
}
return 0;
}
You have three options:
trial and error: try to read a float, and in case of error clear the error flag, ignore the bad input and read again. The problem is that you don't know really how many of the input is to be ignored.
read strings: read space delimited strings, try to convert the string using stringstream, and just ignore the full string in case of error. The problem is that if the input starts with a valid float but then contains invalid characters (e.g. 12X4), the invalid part will be ignored (e.g. X4)
control parsing: read space delimited strings, try to convert the string using std::stof(), and check that all characters of the string where successfully read
Here the second approach, with a slightly restructured loop, so that a 0 entry will lead to exiting the loop and not the full program:
string input;
while(cin >> input)
{
stringstream sst(input);
if (sst>>numb) {
sum += numb;
cout << "Sum equals: " << sum << endl << endl;
if (numb==0)
{
cout << "Entered 0." << endl;
break; // exits the while loop
}
cout << "Enter another number: ";
}
else
{
cout << "Ignored entry "<<input<<endl;
}
}
cout << "Press Enter to terminate the app." << endl;
Online demo
If you prefer a more accurate parsing, consider something like:
size_t pos=0;
float xx = stof(input, &pos );
if (pos!=input.size()) {
cout << "error: invalid trailing characters" <<endl;
}
You have to clear the failbit after a failed read. After that, you can read in the invalid stuff into a string (that you just ignore). This function will read in values and add them up until it encounters a 0 or the end of the input stream.
int calc_sum_from_input(std::istream& stream) {
int sum = 0;
// If it couldn't read a value, we just read the thing into here
std::string _ignored;
while(stream) // Checks if the stream has more stuff to read
{
int value;
if(stream >> value)
{
if(value == 0) // Exit if it read the value 0
break;
else
sum += value; // Otherwise update the sum
}
else {
// Clear the failbit
stream.clear();
// Read ignored thing
stream >> _ignored;
}
}
return sum;
}
The logic is basically:
set the initial sum to 0
check if there's stuff to read
if there is, try reading in a value
if successful, check if the value is 0
if it's 0, exit and return the sum
otherwise, add the value to the sum
otherwise, clear the failbit (so that you can read stuff in again) and read the bad value into a string (which gets ignored)
otherwise, return the value

c++ accepting 0 into while loop illegally

Here is the objective: "Write a c++ program which prompts the user to enter some numbers and finds the minimum, maximum, and count
(number) of the entered numbers separately for the positive and negative numbers. It then prints out this information
in the correct format. Entering 0 should terminate the input sequence and cause the results to be displayed.
My problem is, when I run the code through www.cpp.sh, it seems to be storing the 0 that I use to end the sequence to a maximum or a minimum variable (posmax and negmax or posmin and negmin). My while loop's condition is number_entered !=0, so 0 shouldn't even be going into the loop...
if the first 3 in the sequence are negative and the last 3 are positive; if the first 3 in the sequence are positive and the last 3 are negative
Stranger still, the 0 being stored as a minimum or negative only seems to happen to the last sequence of variables entered.
Relevant code:
int main()
{
double number_entered, posmax, posmin, negmax, negmin;
int positive_count, negative_count;
positive_count = 0;
negative_count = 0;
posmax = 0;
posmin = 0;
negmax = 0;
negmin = 0;
//before it goes into a loop it will do the following:
cout << "Entering 0 will terminate the sequence of values.\n" << endl;
cout << "Enter a number: ";
cin >> number_entered; //stores input to number_entered
if (number_entered > 0) //if positive
{
posmax = number_entered; //needs to be initialized before use in loop
posmin = number_entered; //needs to be initialized before use in loop
}
else if (number_entered < 0) //if negative
{
negmax = number_entered; //needs to be initialized before use in loop
negmin = number_entered; //needs to be intiialized before use in loop
}
while (number_entered !=0) //will keep looping as long as the while condition is true
{
if (number_entered > 0) //branch if number_entered is positive
{
if ( number_entered > posmax) //sub-branch to compare to get max
{
posmax = number_entered; //if number is larger than the current max, it gets stored as the new max
}
else if ((number_entered < posmin)||(posmin == 0)) //sub-branch to compare to get min; since posmin is initialized to 0 it needs to be updated
{
posmin = number_entered; //if number is less than min than it gets stored as the new min
}
positive_count++; //under main if branch for if the number is positive, add to positive_count
}
else if (number_entered < 0) //branch for if number_entered is negative
{
if ( number_entered > negmax) //sub-branch if number_entered is more than the max
{
negmax = number_entered; //it then gets stored as the new negmax
}
else if ((number_entered < negmin)||(negmin == 0)) //sub-branch if number_entered is less than min; since negmin is initialized to 0 it needs to be updated
{
negmin = number_entered; //it then gets stored as the new negmin
}
negative_count++;
}
cout << "Enter a number: "; //prompts for input again after it is done counting, and comparing to store a max and min
cin >> number_entered;
} //end of while loop
if (number_entered == 0)
{
cout << endl;
if ((negative_count > 0) && (positive_count > 0)) //for situations where it received both positive and negative values
{
cout << "There were " << negative_count << " negative values entered, with minimum "<< negmin << " and maximum " << negmax << endl << endl;
cout << "There were " << positive_count << " positive values entered, with minimum "<< posmin << " and maximum " << posmax << endl<< endl;
}
else if (negative_count > 0 && positive_count == 0) //for sitautions where only negative input was received
{
cout << "There were " << negative_count << " negative values entered, with minimum "<< negmin << " and maximum " << negmax << endl << endl;
cout << "No positive numbers were entered" << endl;
}
else if (positive_count > 0 && negative_count == 0) //for situations where only positive input was received
{
cout << "There were " << positive_count << " positive values entered, with minimum "<< posmin << " and maximum " << posmax << endl<< endl;
cout << "No negative numbers were entered" << endl;
}
else if (negative_count == 0 && positive_count == 0) //for if only 0 was received
{
cout << "No positive numbers were entered.\n"
<< endl
<< "No negative numbers were entered.\n"
<< endl;
} //end of nested branching if-else if statement
} //end of if statement
return 0;
}
I figured it out finally, but maybe I posted the answer badly and that was why I didn't get the answer I needed.
in order to get a max that wasn't 0 for the negative values, I simply needed to move my || (negmax == 0) condition to the correct if statement (it was on the minimum branch).
There were no other issues with the program.
Because your initial values are zeros. There is no way that you will enter number lower (for positives) and higher (for negatives) than zero.

Keeping track of which is the smallest and which is the largest value so far in a loop

could you please help me with solving simple problem? I am very fresh with C++ and learning from book "Programming: Principles and Practice Using C++ by Bjarne Stroustrup". I have never learnt C++ before so I am not familiar with many useful features. The drill says:
"6. Now change the body of the loop so that it reads just one double
each time around. Define two variables to keep track of which is the
smallest and which is the largest value you have seen so far. Each
time through the loop write out the value entered. If itโ€™s the
smallest so far, write the smallest so far after the number. If it is
the largest so far, write the largest so far after the number"
I do not know how to do this correctly without using vector. Here is my code:
#include "C:/std_lib_facilities.h"
int main()
{
double a, b,differ=0;
char c=' ';
cout << "Enter two values: \n";
while (c != '|' && cin >> a >> b )
{
if (a > b)
{
cout << "The smaller value is: "<< b << " and the larger value is: " << a << "\n \n";
differ = a - b;
if (differ < 1.0 / 100)
cout << "Numbers are almost equal\n\n";
}
else if (a < b)
{
cout << "The smaller value is: " << a << " and the larger value is: " << b << "\n \n";
differ = b - a;
if (differ < 1.0 / 100)
cout << "Numbers are almost equal\n\n";
}
else
{
cout << "These values are equal!\n";
}
cout << "Enter a character | to break loop: \n";
cin >> c;
}
cout << "You have exited the loop.\n";
keep_window_open();
}
And here are previous steps, these I have solved with code above:
Write a program that consists of a while-loop that (each time around the loop) reads in two ints and then prints them. Exit the
program when a terminating '|' is entered.
Change the program to write out the smaller value is: followed by the smaller of the numbers and the larger value is: followed by the
larger value.
Augment the program so that it writes the line the numbers are equal (only) if they are equal.
Change the program so that it uses doubles instead of ints.
Change the program so that it writes out the numbers are almost equal after writing out which is the larger and the smaller if the two
numbers differ by less than 1.0/100.
Could you give me some hint how to do step 6.? I had some ideas but none of them worked..
Here is new code:
#include "C:/std_lib_facilities.h"
int main()
{
double smallestSoFar = std::numeric_limits<double>::max();
double largestSoFar = std::numeric_limits<double>::min();
double a,differ=0;
char c=' ';
cout << "Enter value: \n";
while (c != '|' && cin >> a)
{
if (a > largestSoFar)
{
largestSoFar = a;
cout <<"Largest so far is: "<< largestSoFar << endl;
}
else if (a < smallestSoFar)
{
smallestSoFar = a;
cout <<"Smallest so far is: "<< smallestSoFar << endl;
}
else if(smallestSoFar >= a && a<=largestSoFar)
cout << a << endl;
cout << "Enter a character | to break loop: \n";
cin >> c;
}
cout << "You have exited the loop.\n";
keep_window_open();
}
I do not know how to do this correctly without using vector.
You do not need vector for this. The description correctly says that two variables would be sufficient:
// Declare these variables before the loop
double smallestSoFar = std::numeric_limits<double>::max();
double largestSoFar = std::numeric_limits<double>::min();
Modify your loop to read into a, not into both a and b. Check the newly entered value against smallestSoFar and largestSoFar, do the printing, and re-assign smallest and largest as necessary. Note that the first time around you should see both printouts - for largest so far and for smallest so far.
Based on the knowledge that you are suppose to know at the current stage for the this assignment. The code should go something like this:
#include < iostream>
#include < cstdlib>
int main() {
double num_1 = 0;
double num_2 = 0;
double largest = 0;
double smallest = 0;
bool condition1 = true;
while (true) {
std::cin >> num_1;
if (num_1 > largest){
largest = num_1;
}
else if (num_1 < smallest) {
smallest = num_1;
}
std::cout << "The largest so far: " << largest << std::endl;
std::cin >> num_2;
if (condition1) {
smallest = largest;
condition1 = false;
}
if (num_2 < smallest) {
smallest = num_2;
}
else if (num_2 > largest) {
largest = num_2;
}
std::cout << "The smallest so far: " << smallest << std::endl;
}
system("pause");
return 0;
}
double large = 0;
double small = 0;
double input;
int counter = 0;
while (counter < 5) {
cin >> input;
cout <<"Large value: "<< large << '\t' <<"Small value: "<< small\
<< '\t' <<"Input value: "<< input << '\n';
if (input < small) {
cout << "The smallest value is " << input<<\
"\nthe largest value is "<< large<<'\n';
small = input;
}
else if (input > small&& input < large) {
cout << "The smallest value is " << small << \
"\nthe largest value is " << large<<'\n';
}
else if (input > small&& input > large) {
cout << "The smallest value is " << small << \
"\nthe largest value is " << input << '\n';
large = input;
}
counter += 1;

vector-related segmentation fault

void offer_help();
bool play_one_game();
int main() {
offer_help();
play_one_game();
}
void offer_help() {
int help_response;
cout << "Need help? (0/1) ";
cin >> help_response;
if (help_response == 1)
cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n Each guess that you enter will be a line containing 4 integers,\n separated by spaces, such as:\n\t 2 4 7 1\n FOr each guess, I will echo back a lost consisting of\n 0's and 1's, with a 1 in a given position meaning that\n you guessed the number, and a zero meaning that you didn't.\n For example, if the actual solution was 2 3 6 1, I'll respond\n\t 1 0 0 1\n See how many guesses it takes you to get the solution!\n\n If you want to give up, type a negative number for one of\n your guesses, and we'll tell you what the pattern was.\n\n";
}
bool play_one_game() {
srand(time(0)); //needed to start randint
vector<int> solution; //vector of 4 randomly generated
//solutions
vector<int> guess; //vector containing user guesses.
vector<int> result;
int guess_input;
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
int trial_number = 0; //int that shows what guess the user is on
while (play_one_game() == true) {
//ask user for inputs.
cout << "Guess #" << ++trial_number << "? ";
for (int i = 0; i < guess.size(); ++i){
cin >> guess_input;
guess.push_back(guess_input);
}
//outputs error if user inputs a letter.
if (!cin) {
cerr << "Bad input data! Feed me numbers!\n";
return 43;
}
if (cin < 0){
cout << "Too bad! Solution was " << endl;
for(int i = 0; i < result.size(); i++)
cout << (result[i]);
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
for (int i = 0; i < result.size(); i++) {
if (guess[i]==solution[i])
cout << 1 << " ";
else if (guess[i]!=solution[i])
cout << 0 << " ";
}
cout << endl;
// playagain();
cout << endl << "Play again (0/1)? ";
int replay;
cin >> replay;
if (replay == 0) {
play_one_game() == false;
return 5;
}
else if (replay == 1)
play_one_game() == true;
else {
cerr << "wat?\n";
return 10;
}
}
}
This is designed to allow a player to guess a pattern of random numbers.
No idea why I am getting a segmentation fault. The program is supposed to call the offer_help function, then the play_one_game function within main function. Then it should ask the player whether he wants to play again. If no, then bool play_one_game should be set to false and it should exit.
This is related to the play_one_game bool function.
You're getting a segmentation fault, because you end up in an endless recursion in the following line:
while (play_one_game() == true) {
play_one_game will call play_one_game in this line, and this will call play_one_game in the same line again. This will result in a stack overflow at last.
Better use some bool keepPlaying; and while(keepPlaying) instead.
EDIT: Well, this is a little bit more than a simple answer, but I like games, so... have a look at the following code:
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
bool play_one_game();
void offer_help() {
int help_response;
std::cout << "Need help? (0/1) ";
std::cin >> help_response;
if (help_response == 1)
std::cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n"
"Each guess that you enter will be a line containing 4 integers,\n"
"separated by spaces, such as:\n"
"\t 2 4 7 1\n"
"For each guess, I will echo back a lost consisting of\n"
"0's and 1's, with a 1 in a given position meaning that\n"
"you guessed the number, and a zero meaning that you didn't.\n"
"For example, if the actual solution was 2 3 6 1, I'll respond\n"
"\t 1 0 0 1\n"
"See how many guesses it takes you to get the solution!\n\n"
"If you want to give up, type a negative number for one of\n"
"your guesses, and we'll tell you what the pattern was.\n\n";
}
int main() {
offer_help();
srand(time(0)); // Initialize random numbers with current time as seed
while(play_one_game()); // if play_one_game returns true, play again
}
bool play_one_game() {
std::vector<int> solution(4); // Four solutions for our guessing game
std::vector<int> guess; // User guesses
for(unsigned i = 0; i < solution.size(); ++i)
solution[i] = rand() % 10;
int trial_number = 0; //int that shows what guess the user is on
bool keepPlaying = true;
while(keepPlaying){
std::cout << "Guess #" << ++trial_number << "? ";
guess.clear(); // Clear old guesses
for(unsigned i = 0; i < solution.size(); ++i){
int guess_input;
//outputs error if user inputs a letter.
if (!(std::cin >> guess_input)) {
std::cerr << "Bad input data! Feed me numbers!\n";
std::cerr << "Try again!" << std::endl;
std::cin.clear(); // Clear flags
continue;
}
if (guess_input < 0){
std::cout << "Too bad! Solution was " << std::endl;
for(unsigned i = 0; i < solution.size(); i++)
std::cout << (solution[i]);
keepPlaying = false;
break;
}else
guess.push_back(guess_input);
}
if(!keepPlaying)
break;
if(solution.size() != guess.size()){
std::cerr << "Wrong number of guesses, try again!" << std::endl;
continue;
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
bool correct = true;
for (unsigned i = 0; i < solution.size(); i++) {
if (guess[i] == solution[i])
std::cout << 1 << " ";
else{
correct = false;
std::cout << 0 << " ";
}
}
if(correct){
std::cout << "Congratulations - you won!" << std::endl;
break;
}
std::cout << std::endl;
}
int replay = -1;
do{
// Ask user for input until input is 0 or 1
std::cout << std::endl << "Play again (0/1)? ";
std::cin >> replay;
}
while(replay != 0 && replay != 1);
return static_cast<bool>(replay); // return user replay answer (false/true)
}
Try to keep your code as simple as possible. Welcome to SO. And don't expect future answers to be that excessive.
You're never inserting anything into your solution vector. You just declare the vector, and then say:
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
...which won't do anything since at this point solution.size() == 0. Later, when you iterate over your result vector, you end up accessing invalid elements in your empty solution vector. You also can't assume that the result vector and solution vector are the same size.