I'm asking the user to select a choice between items in a backpack by entering an integer corresponding to the item. But despite my current integer input validation code, the whole program terminates instead of redisplaying the choices and asking the user to enter a choice again. Is there anything problematic in the code below that may be causing this?
int num;
do{
std::cout << "Choose item to use." << std::endl;
for(int i = 0; i < backpack->size(); i++){
std::cout << i+1 << ". " << backpack->at(i) << std::endl;
};
std::cin >> num;
if(!std::cin.fail()){
if(num < 0 || num > (backpack->size())){
std::cout << "Plese enter an integer in range." <<std::endl;
}else{
break;
};
}else{
std::cin.clear();
std::cin.ignore(80, '\n');
std::cout << "Invalid input. Please enter an integer." << std::endl;
};
}while(std::cin.fail() || (num<0 || num > (backpack->size())));
You have to assign an initial value to num. If you don't, it will contain a garbage value, which is possibly less than 0 or greater than backpack->size()-1, which will make the condition true.
int num = 0;
Edit: Scraped last answer
The following clear the cin.fail() flag:
std::cin.clear();
std::cin.ignore(80,'\n');
So upon reaching the loop condition, cin.fail() returns false and the unitialized num most likely contains 0. Thus, your continuation condition does not pass and the loop returns.
As suggested by #Eddge, you should initialize num to an invalid value in regards to your condition, like -1.
After looking over the code a few times, I don't immediately see a problem with the logic, though I could be wrong. But from what I understand is the intention of the code, the condition in the while statement is redundant and unnecessary. You are already checking those same conditions in the if statements and breaking out of the loop when needed, so try using while(true) as your while statement and see if it fixes your problem.
I just found that changing "std::cin.fail()" to "!(std::cin>>num)" in the while condition did the trick. Why do you think that is? By the way, thanks for all of your input!
Related
In C++, how do you handle wrong inputs? Like, if the program asks for an integer, when you type a character it should be able to do something and then loop to repeat the input but the loop goes infinite when you input a character when an integer is need and vice versa.
The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.
//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}
See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.
Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.
The top voted answer covers the solution really well.
In addition to that answer, this may help visualize what's going on a little better:
int main()
int input = 1;//set to 1 for illustrative purposes
bool cinState = false;
string test = "\0";
while(input != -1){//enter -1 to exit
cout << "Please input (a) character(s): ";//input a character here as a test
cin >> input; //attempting to input a character to an int variable will cause cin to fail
cout << "input: " << input << endl;//input has changed from 1 to 0
cinState = cin;//cin is in bad state, returns false
cout << "cinState: " << cinState << endl;
cin.clear();//bad state flag cleared
cinState = cin;//cin now returns true and will input to a variable
cout << "cinState: " << cinState << endl;
cout << "Please enter character(s): ";
cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
cout << "test: " << test << endl;
}
return 0;
}
Dumping the text in the buffer to a variable isn't particularly useful, however it helps visualize why cin.ignore() is necessary.
I noted the change to the input variable as well because if you're using an input variable in your condition for a while loop, or a switch statement it may go into deadlock, or it may fulfill a condition you weren't expecting, which can be more confusing to debug.
Test the input to see whether or not it is what your program expects. If it is not, alert the user that the input they provided is unacceptable.
You can check it through the ASCII value if the ascii value s between 65 t0 90 or 97 to 122 the it would be character.
I'm trying to get a simple tic-tac-toe program to function in the console as a way to make sure I understand loops and arrays.
It compiles, and runs as expected, with the exception that if a user inputs something that isn't a number the program races through the first if statement infinitely without a chance to add a new input. I really can't see how to fix this.
I think the issue is that chosenSquare is an integer as it needs to be compared to values, but cin can take anything in. Expected behaviour would be to check if the input is an integer between 0 and 8 (the 9 spaces on the board), and if not return a message and repeat, waiting for a new input.
Is there a simple fix for this? I'm trying to avoid specialist packages and namespaces for now while I grok the basics. I've looked at similar problems but don't follow them.
Thanks.
Code snippet:
// Input loop
bool valid = false;
while (valid != true)
{
int chosenSquare = 0;
cout << "Player " << currentPlayer << ", enter a number between 1 and 9:" << endl;
cin >> chosenSquare;
chosenSquare--; // For array indexing
if ((chosenSquare < 0) || (chosenSquare > 8)) // <--- PROBLEM IS THIS LOOP
{
cout << "Invalid input. Try again." << endl;
continue;
}
else if ((board[chosenSquare] == currentPlayer) || (board[chosenSquare] == lastPlayer))
{
cout << "Square not availible. Try again." << endl;
continue;
}
else
{
board[chosenSquare] = currentPlayer;
valid = true;
break;
}
}
There are a couple of things culminating causing this.
The first is that when an alpha character is put into the console, the error bit is set, and 0 is written to the variable you're writing to:
The behavior you want to observe changed in 2011. Until then:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
But since C++11:
If extraction fails, zero is written to value and failbit is set. [...]
(From cppr.)
That means chosenSquare is 0 after the read, so chosenSquare-- makes it -1. -1, as you know, is less than 0, so the first if-statement is true.
As to why it stays this way infinitely, you need to clear the fail-bit.
So I changed the first loop after a bit of reading and experiementation:
if (cin.fail()) // <--- PROBLEM IS THIS LOOP
{
cout << "Invalid input. Try again." << endl;
cin.clear();
cin.ignore();
continue;
}
This works, but I can't figure out what it's actually doing.
Could anyone elaborate?
void getPlayerRolls(int RollValues[], int& AttemptCount) {
int i = 0;
int FrameNumber = 0;
int RollNumber = 0;
while(RollValues[i] != -1) {
FrameNumber++;
cout << "Frame # " << FrameNumber << endl;
cout << "Roll #1 "
<< " ";
cin >> RollValues[i];
i++;
cout << "Roll #2 "
<< " ";
cin >> RollValues[i];
i++;
cout << endl;
}
}
My expectation is that when a -1 is entered for one of the roll values that the program terminates. I tried to create a while loop that works with an array but I am having trouble determining how to do this.
I removed lines from your function that are not part of the problem, but maybe this will clarify:
while(RollValues[i] != -1) {
cin >> RollValues[i];
i++;
cin >> RollValues[i];
i++;
i++;
}
What is the value of i by the time the loop condition variable is tested?
The first rollvalue entered is read into some place in the array, but then i is incremented, so if you read back from RollValues[i] you read from a different place in memory! Not only that, you never look at the first roll before accepting the second. And then you increment i yet again. By the time you're back at the top of the loop, i has been advanced 3 times, and neither of the entered rolls is ever tested.
You have other issues too, such as
receiving an array has no "size" information associated, so you do not now how big of an array the caller provided. Your code therefore cannot protect against overruning the memory.
in your while loop, you advance 3 times per iteration, so even if your loop condition checks for boundary cases, you still could have walked off the end of the array before getting back to the top of the loop.
Therefore, I suggest the following:
1) pass in the size of your array into your function, or use a safer data structure, such as std::array or std::vector
2) only process a single roll per loop, and check that you're within bounds before advancing.
3) don't advance your index variable until you're done looking at the value in that place that it refers.
I just completed a program that has to quit when a negative value is entered as input. Everything is working good except for only one issue, it quits the program after the second time a negative value is entered. After some research I noticed the use of break, however the samples I have to guide the assignment use only if and else statement.
#include <iostream>
using namespace std;
int main()
// insert code here...
// create a variable named "pounds" that can be used to store an integer.
// wait for the user to type in a value and put that value into the variable ounces
{
int poundsTotal;
int ouncesTotal;
while (poundsTotal >= 0)
{
cout << "Enter pounds or a negative number to quit: ";
cin >> poundsTotal;
ouncesTotal = poundsTotal * 16;
cout << poundsTotal << " pouds is " << ouncesTotal << " ounces." <<endl;
cout << " Enter pounds or a negative number to quit ";
cin >> poundsTotal;
poundsTotal++;
}
if (poundsTotal == 0){
cout <<"you enter a zero value" <<"Try onemore time";
}
else {
cout << "you chose to quit the program" <<poundsTotal;
}
}
The condition of a while loop is evaluated after the body has been executed. Then it is determined whether the body will be run again. Change your code and add an if statement inside the loop.
if(poundsTotal < 0) break;
And yes, a break statement is useful in a loop. Otherwise you can't stop the loop before your test condition is evaluated to false.
In your case, I find using a break would be a simple option.
When the program first reaches while (poundsTotal >= 0), poundsTotal has no defined value. This puts you at the mercy of the gods as to whether the program will work as expected or not, and Gods are notoriously unreliable. For more information, look up the term Undefined Behaviour.
The solution to this is ask the user for poundsTotal before the loop and once more at the end of the loop.
If you want to get really posh and do this without repeating code (and stay DRY) , make a function that gets poundsTotal from the user and call this function in the while loop's condition. For example,
while ((poundsTotal = getPoundsTotal()) >= 0)
{
...
}
In C++, how do you handle wrong inputs? Like, if the program asks for an integer, when you type a character it should be able to do something and then loop to repeat the input but the loop goes infinite when you input a character when an integer is need and vice versa.
The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.
//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}
See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.
Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.
The top voted answer covers the solution really well.
In addition to that answer, this may help visualize what's going on a little better:
int main()
int input = 1;//set to 1 for illustrative purposes
bool cinState = false;
string test = "\0";
while(input != -1){//enter -1 to exit
cout << "Please input (a) character(s): ";//input a character here as a test
cin >> input; //attempting to input a character to an int variable will cause cin to fail
cout << "input: " << input << endl;//input has changed from 1 to 0
cinState = cin;//cin is in bad state, returns false
cout << "cinState: " << cinState << endl;
cin.clear();//bad state flag cleared
cinState = cin;//cin now returns true and will input to a variable
cout << "cinState: " << cinState << endl;
cout << "Please enter character(s): ";
cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
cout << "test: " << test << endl;
}
return 0;
}
Dumping the text in the buffer to a variable isn't particularly useful, however it helps visualize why cin.ignore() is necessary.
I noted the change to the input variable as well because if you're using an input variable in your condition for a while loop, or a switch statement it may go into deadlock, or it may fulfill a condition you weren't expecting, which can be more confusing to debug.
Test the input to see whether or not it is what your program expects. If it is not, alert the user that the input they provided is unacceptable.
You can check it through the ASCII value if the ascii value s between 65 t0 90 or 97 to 122 the it would be character.