C++ Input Validation to avoid ability to break code - c++

I have written a program that simulates a fishing game. The program is inside a running loop to iterate as long as the user wishes. The issue is that anything that is entered, other than 1 or 0, breaks my code. I have been trying different things for hours now, and I need some help! My main cpp file code is included. Please let me know if my header files are needed for your review as well.
It has been requested for me to edit the code. The problem is that anything other than an integer breaks my code when entered. I do not want this. I want the program to catch the input and continue looping until the user enter's the right input ( 1 or 0) or quits the game.
Game game; // Game object game declared
cout<<"Welcome to Go Fish 2.0!"<<endl; // welcome message
cout<<"Would you like to play?"<<endl; // Prompts user to play
cout<<"1 to play, 0 to exit:"<<endl; // Provides user with input choices
cin>>choice; // user enters game play choice
if (choice == 1) // while user chooses to play game
play = true; // play boolean is set to true
else if (choice == 0) // while user chooses to end game
play = false; // play boolean is false
while ( ! cin>>choice) { // while user entry is not valid
// display correct inpout choices again
cin.clear();
cin.ignore (100, '\n');
cout <<"You entered invalid data. Please enter the numerical value 1 if you want to play again or 0 if you dont."<<endl;
cin >> choice; // hopefully user enters valid input
if (choice == 1) { // if user chooses proper input after improper input
play = true;// play boolean is set to true
break;// break
}
}
total=0; // variable total is initialized to 0
while (play == true) { // while play boolean is set to true; user wants to play game
total1 += game.playgame(total); // total1 variable keeps a running total of the game
//game.playgame(total) uses the game object to call the playgame function that passes the variable total
// when game.playgame(total) is called this funciton essentially mobilizes game play of die rolling and point accumulation
//each time this function is called (as many times as user wants to play game), the running total is incremented
cout<< "Do you want to play again? (0 for no, 1 for yes)"<<endl;// asks user if they want to play again
cin >> choice;// user enters choice
if (choice == 1) // if user enters 1
{
play = true; // play is assigned to true
}
else if (choice == 0) // if user enters 0
{
play = false; // play is assigned to false
}
/*
while ( ! cin>>choice) { // while user entry is not valid
// display correct inpout choices again
cin.clear();
cin.ignore (100, '\n');
cout <<"You entered invalid data. Please enter the numerical value 1 if you want to play again or 0 if you dont."<<endl;
cin >> choice; // hopefully user enters valid input
if (choice == 1) { // if user chooses proper input after improper input
play = true;// play boolean is set to true
break;// break
}
}
if (choice == 1) { // if user chooses proper input after improper input
play = true;// play boolean is set to true
break;// break
cout<<"My Total game points are "<<total1<<endl; // displays user's total points from whole game
if (total1>100) // if game total greater than 100
cout<<"Awesome! You're a great fisher!"<<endl; // congratulate user
if (total1<100)// if game total is less than 100
cout<<"Good job, but play again so you can fish some more."<<endl;// chastise user
system("pause");
}
}
return 0;// end main function
}
}

You should take input from the user as a string/character array first and then attempt to convert it to an int (there are a number of ways to do this - Google is your friend ;)) but atoi (ASCII to int) is probably the quickest/simplest. If that fails, ask the user to enter a valid input, repeat until you get a 1 or 0, something like that.

There are multiple places where you expect input. I couldn't make much sense of your code.
Based on your description you just need one place to read the integer: a loop reading the choice and verifying the correct input was received. That should be rather straight forward...
for (int choice(0); true; ) {
std::cout << "some message goes here\n";
if (std::cin >> choice) { // successfully read a value
if (choice == 0) { // the choice is to stop
break;
}
else if (choice == 1) { // the choice is to carry on
play_again();
}
else { // an invalid choice was made
std::cout << "value " << choice << " is out of range\n"
}
}
else if (std::cin.eof()) { // input failed because nor more input
break;
}
else { // a non-integer was entered
std::cout << "a non-integer was entered\n";
std::cin.clear(); // clear error state and ignore current line
std::cin.ignore(std::numeric_limits<std::streamsize>::max();
}
}

Related

Intro to classes (c++) project wants us to create two constructors, but neither of them need any parameters - what should i do here?

I think I'm just confused on the wording to this project, but I'm posting here to make sure I have the basics on classes correct (like I said, we just started learning them).
The beginning of the project prompt is as follows:
Declare and define a class called Odometer. This class will have two private variables, one for the miles driven and the other for the gallons of gas pumped into the car.
The member functions should include:
A constructor that takes initial values for both of the private variables.
A default constructor that sets both values to zero.
Along with more member functions that aren't important for my problem. I understand the default constructor fully, but the other is the one I'm having troubles with. If he (my professor) wants us to gather initial variables, then why would it need any parameters at all? I guess I could pass an empty string into it as a parameter, but I feel like there's something I'm missing here...
To expand on the point of this project, in case it's needed, we are creating a program that allows the user to continually enter (on a menu screen) either miles driven or gallons put into their tank. The program will then find the mpg, when the user requests it. Very simple.
Here's part of the program, which should be enough for someone to help me with this. The second/non-default constructor seems like it would work, except obviously I need some type of parameter. Any suggestions or help is greatly appreciated.
#include <iostream>
using namespace std;
class Odometer{
public:
Odometer(); // sets values to 0
Odometer(WHAT GOES HERE); // gathers initial values
void get_miles();
void get_gallons();
void add_in_trip_miles();
void add_gas();
private:
double milesDriven; // represents the miles the car has driven
double gallonsGas; // represents the number of gallons pumped into car
};
int main() {
Odometer userInfo; // creates object for the user-inputted values
bool quit = false; // true when user wants to quit
int userChoice; // for navigating the menu screen
while(!quit){
cout << "To view total miles, enter 1. To view total gallons, enter 2.\nTo record more miles driven, enter 3. To record gallons pumped into the tank, enter 4.\n To view the average MPG, enter 5. To reset the odometer, enter 6.\n To quit the program, enter 7." << endl;
cin >> userChoice;
if(userChoice == 1) userInfo.get_miles(); // TODO: switch/case statement instead?
if(userChoice == 2) userInfo.get_gallons();
if(userChoice == 3) userInfo.add_in_trip_miles(); // TODO: "function which increases the miles by the amount sent in its parameter
}
cout << "Have a nice day!" <<endl;
return 0;
}
Odometer::Odometer(){ // sets values to 0 (default)
milesDriven = 0;
gallonsGas = 0;
}
Odometer::Odometer(WHAT GOES HERE?){ // gathers initial values
cout << "Please enter an initial value for miles driven." << endl;
cin >> milesDriven;
cout << "Please enter an initial value for how many gallons were put into the car." << endl;
cin >> gallonsGas;
}
Your teacher is asking you to implement the second constructor with parameters so user will be able to initialize the object with the state he wants. I would implement it like this:
Odometer(double milesDriven_, double gallonsGas_) :
milesDriven(milesDriven_),
gallonsGas(gallonsGas_)
{}

C++ - fgets() ignores subsequent inputs if Enter is pressed

I am trying to create an emulator for something, and in the main loop for the processor I wanted to implement a simple way to step the CPU one loop at a time (prompted by pressing Enter each loop) so I can see what instructions are being executed each step. In addition, it allows you to enter a number instead of just Enter to change the default step amount from 1 to something else (so it will skip x number of cycles and then return to 1 at a time afterwards.
The issue is that it works fine when I enter a number (skip that amount of cycles and then prompts me again each cycle), but when I just press Enter rather than entering a number I want it to default to 1 step. Instead, pressing Enter causes it to just run through the whole program without ever prompting me again. How do I make Enter == 1?
void CPU_loop()
{
...
static int step = 1;
char cmd[10];
if(step == 1)
{
if(fgets(cmd, 10, stdin) != NULL) // If you entered something other than Enter; doesn't work
{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}
else
{
--step;
}
...
}
When you press enter directly, it does not default to 1, but instead you are passing the string "\n" to std::atoi(), std::atoi() cannot be used to perform sanity check on it's input, you can use a different function for that like std::strtol() or, you can simply add
if (step == 0)
step = 1;
because when, std::atoi() takes a "\n" as input, it returns 0. Read the documentation to further understand it.
Quoting the documentation
Integer value corresponding to the contents of str on success. If the converted value falls out of range of corresponding return type, the return value is undefined. ​If no conversion can be performed, 0​ is returned.
One more thing, you could do it the c++ way using streams for input to avoid all this.
You could do:
if (fgets(cmd, 10, stdin) != NULL)
{
if (cmd[0] == '\n'){
step = 1;
}
else{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}

how to loop in nested if else statement

we are currently creating a mini game for our school project.
the game code is already done but im currently doing some introduction.
i was thinking of putting the mechanics of the game when you run the program and i want to put a menu.
ex.(press 1 to play , press 2 to exit) im already done with the code for the nested if too but i don't know the code for looping it back to asking a number if the user enter a number that's not indicated for example the number 3. I want to loop it back to asking a number until the user input a valid number.
If you are trying to exit the "if" statement, I think you want to use:
continue;
If you are in a switch/case, you would use:
break;
Just create a level.Then if your input doesn't satisfy the conditions ,then jump that level again using goto level and take input again untill it satifies the conditions.
karim:
int a;
cin>>a;
if(a==1){....do what...}
else if(a==2) { ...do what...}
else
goto karim;
Just put all of your actions in a while() cycle and write something like that:
while ((key = getch()) != *exit key*){
if (key == ...){ action 1; }
else if (key == ...){ action 2; }
else if (key == ...){ action 3; }
}

Getting stuck in an infinite loop

I had my program running smoothly, and then after commenting it and adding some final touches, it stopped working on me. The function that I am having problems with is using several objects/functions defined elsewhere, so I am just wondering if someone can affirm that my logic is correct and that the infinite loop is not a product of a syntax error. Thanks for your time, here is the problem I'm having:
If the cashier started a new order and wants to close his order, T is typed in. However, when trying to exit an order and loop back to the start of while(moreCustomers), nothing is happening. I am trying to exit the while(moreItems) loop by setting moreItems = false;, but after doing that, it gets stuck in the while(moreItems) loop and does not go back to while(moreCustomers). Does the syntax make sense, and should I be able to break the loop by setting moreItems = false;?
bool moreCustomers = true;
while (moreCustomers)
{
// get input to start new order or close register
drawInstruct("Enter N to start a new order or E to\n close the register.");
char* setFmt = "#"; // the input must be a letter
char input[7]; // char array that stores input from cashier
s.GetStr(xLeftCoord + 1, yTopCoord + 1, input, 1, setFmt, true);
for(int x = 1; x < 10; x++) // clear the input field
{
s.ClearScreenPos(x, 1);
}
if (input[0] == 'N') // if a new order is requested
{
bool moreItems = true;
while (moreItems)
{
getInput(input);
if(input[1]) // if input is not a single char
{
if (input[0] == 'M') // get the desired number of multiples for the current item and update the tape and display area accordingly
{
custTape.handleMultiples(atoi(input)); // adds multiples to tape
curVal = isUPC->price * (atoi(input)); // updates the current item price
drawDisplayArea(curVal); // updates the display area
}
else // invalid number of multiples, prompt for new multiple
{
drawInstruct("Invalid command. Please try again.");
s.Delay();
}
}
else if (input[0] == 'T') // close the order
{
drawInstruct("Order cancelled.");
s.Delay();
moreItems = false; // customer order is complete, exit loop
}
else // invalid command, get new input from the cashier
{
drawInstruct("Invalid command. Please try again.");
s.Delay();
}
}
}
else if (input[0] == 'E') // close the register
{
moreCustomers = false; // no more customers, exit the program
}
else // invalid command, get new input from the cashier
{
drawInstruct("Invalid Command. Please try again.");
s.Delay();
}
}
I can't exit else if(input[0] == 'T'), and any commands I enter in after moreItems = false; work correctly.
I'd set a breakpoint on the first moreItems = false; line to see if it is ever being hit. My guess is that it is not. You've tagged the question with Visual Studio, so if that is what you're using see this link for how to set a breakpoint:
http://msdn.microsoft.com/en-us/library/vstudio/k80ex6de%28v=vs.100%29.aspx
Basically a breakpoint causes your program to stop at that line. Also try setting a breakpoint on this line:
if (input[0] == 'N')
Run the program, press a key, and wait for the breakpoint to be hit. Then use the "Step Over" option on the Debug menu. This runs your program line by line, each time you press "Step Over" (F10 does this too, much quicker). Keep stepping to see what path of execution occurs through your code. You may also be able to hover over variables to see their values.
Theres loads on the net about debugging with visual studio, but if you master the above you'll be well away

How do I add a "play again" feature to my C++ guessing game? Loop trouble

So for this assignment I have to include a play again function. Meaning once the person has guessed correctly the program should give the user the choice to play again or not. Also, I am trying to include a function where if the user guesses correctly in 5 guesses or less, then the program should print "Good Job!" and if it takes them more than 5 guesses, it should display "You can do better than that!". Help me please! I am a beginner in programming and I keep getting stuck in trying to fix this problem.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main( void )
{
int i, n = 0, r;
int answer;
srand( time( NULL ) );
r = rand() %100 +1;
char userName[15];
printf("Welcome to GUESS MY NUMBER!\n\nPlease type your name here: ");
scanf("%s", &userName);
printf("\n\nI am thinking of a number between 1 and 100.\n\nCan you guess what it is? ");
while(scanf("%d", &i))
{
if (n >= 9 && i != r)
{
printf("\n\nSorry, the number was %d.\n", r);
printf("You should have gotten it by now.\n");
printf("Better luck next time.\n\n");
system ("PAUSE");
break;
}
if (i > r)
{
n++;
printf("Your guess is high. You only get 10 guesses. Try again: ");
}
else if (i < r)
{
n++;
printf("Your guess is low. You only get 10 guesses. Try again: ");
}
else if (i == r)
{
printf("\n\nCongratulations %s!\nYou guessed the number within %d guesses!\nWould you like to play again? y/n?\n",userName, n+1,answer);
scanf("%d", &answer);
system ("PAUSE");
break;
}
}
return 0;
}
An easy thing to do is create a bool variable (originally set to true) which can be checked in the while statement and updated after the user has been given the option to continue or not. Then just change your breaks into continues and you should be in good shape.
Wrap the whole thing in another loop, and at the end of this outer loop, ask the user if he wants to play again. Either a while() or do-while() loop. If the user says yes, continue looping, otherwise exit the loop.
-Initialize the game
-Load any resources needed (in this case, none)
Begin looping continually
- Handle input
- Think
- Show results
End looping if exited
-Free any resources (in this case, none)
-Exit