Understanding why unwanted iterations of a cout statement occur [duplicate] - c++

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 3 years ago.
I am working with some C++ code. I have a while-loop set up to allow me to run through some code x-number of times. The while loop terminates once the user indicates that they do not want to run through the code again.
#include <iostream>
#include <string>
using namespace std;
char request;
int main() {
while (request != 'N')
{
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code (A or B followed by two-number identification)" << endl;
getline(cin, getCode);
if (getCode.length() != 3)
{
cout << "Error" << endl;
}
}
//clear the screen
system("cls");
//get letter
if (getCode.at(0) == 'A' || getCode.at(0) == 'B')
{
if ((getCode.at(1) >= '0' && getCode.at(1) <= '9') && (getCode.at(2) >= '0' && getCode.at(2) <= '9'))
{
if (getCode.at(0) == 'A')
{
cout << "The shipping charge is $25" << endl;
}
else if (getCode.at(0) == 'B')
{
cout << "The shipping charge is $30" << endl;
}
}
else
{
cout << "Error" << endl;
}
}
else
{
cout << "Error...Please enter the code as A or B followed by two numbers" << endl;
}
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
}
cout << "Thank you" << endl;
//End Program
system("pause");
return 0;
}
When I indicated that yes (entering 'Y' to the 'Would you like to enter in another shipping identification number question') I would like to run through the code again, the program outputs an unwanted 'Please enter your container's region code (A or B followed by two-number identification' and 'error' statement. Also please note, the code is inside 'int main()' and that I have properly formatted my 'include' statements.

Your question is to understand why this is happening, so here's the explanation. The code you wrote states thusly:
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code...
As you see, getCode is always initialized to an empty string. Immediately afterwards, if its length is not 3, this question is outputted.
You need to understand that your computer will always do exactly what you tell it to do. Your computer will not do what you want it to do, but only what you tell it to do. The above is what you told your computer to do, and your computer will always obediently follow its strict instructions, every time it runs this code. That's pretty much the explanation, and there's nothing more to understand.
This section of code is inside another loop, and you indicated that you do not wish the prompt to appear on second and subsequent iteration of the loop, only on the initial one.
However, there's nothing in your instructions to your computer, above, that specify this. You didn't tell your computer that this is what it should do, so why do you expect your computer to do that, entirely on its own? Every time your computer executes these statements shown above, this is exactly what will happen. Nothing more, nothing less. Whether it's the first time inside the outer while loop, or on each subsequent time the while loop iterates, it doesn't matter. The code always does exactly the same thing: getCode gets created and set to an empty string, and because its length is not 3, the inner while loop runs, prints the prompt and calls std::getline to read a line of text from std::cin. At the end of your while loop, if your instructions to your computer indicate that it should run the code in the while loop again, from the beginning (because that's what the while loop does), then the above instructions get executed.
If you now understand why your computer does this (because that's what you told it to do), then you should easily figure out what to tell your computer so it doesn't do this. If you want your computer to print the prompt only the first time it executes the while loop, then this is exactly what you need to tell your computer: set a flag before the while loop, print the prompt only if the flag is set (with all other existing logic remaining the same), and then clear this flag afterwards, so the next time the while loop runs, your computer will do exactly what you told it to do, and not print the prompt.

when I indicate 'Y' to the prompt 'Would you like to enter in another shipping identification number?', it outputs the following: 'Please enter your container's region code (A or B followed by two-number identification)' 'error' 'Please enter your container's region code (A or B followed by two-number identification' . When I input 'Y' I only want it to output 'Please enter your container's region code (A or B followed by two-number identification)'...I only want it to output once
Now that I understand your question, what's happening is an newline (\n) is getting added to the std::cin buffer at these lines right here:
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
This makes even more sense especially when combined with your other comment:
Before int main() there should be a 'char request;
So request a single char. That means when you type something like this:
Y
The newline is added to std::cin as well. That can't be stored in a single char, and the >> may not remove it either. That means it's just sitting here.
What this does is when you get to your if statement at the beginning of the loop again:
while (request != 'N')
{
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code (A or B followed by two-number identification)" << endl;
getline(cin, getCode);
if (getCode.length() != 3)
{
cout << "Error" << endl;
}
}
getline() sees the newline you added previously and instantly returns an empty string. Empty strings have a length of 0, so it fails your if statement, which prints the error.
The solution is simple, just tell std::cin to ignore the newline:
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
cin.ignore(1, '\n');

Related

Infinite loop created when inputting "yy" into a char variable that should only take a single character such as 'y' or 'n', "nn" does not break code

The code in the cont function asks the user if they want to play my game again.
The code works when receiving proper character inputs such as 'y' or 'n' as well as their respective capital letter variants, and the else block works properly to loop the function if an invalid input such as 'a' or 'c' is entered.
However during a test run, an input of 'yy' breaks the code causing the program to infinitely loop, running not only this cont function but my game function as well.
choice is stored as a char variable. I am wondering why the code even continues to run upon inputting multi-character inputs such as 'yy' or 'yes'. What's interesting is 'nn', 'ny' and other variations of multi-character inputs that begin with 'n' causes no issues and properly results in the else if block running as intended. Which prints "Thanks for playing." then ends the program.
Can variables declared as char accept inputs greater than 1 character? Does it only take the first value? And if so why does 'yy' cause a loop rather than the program running as intended by accepting a value of 'y' or 'Y'? How can I change my program so that an input of 'yy' no longer causes issues, without specific lines targeting inputs such as 'yy' or 'yes'.
#include <iostream>
#include <string> // needed to use strings
#include <cstdlib> // needed to use random numbers
#include <ctime>
using namespace std;
// declaring functions
void cont();
void game();
void diceRoll();
// variable declaration
string playerName;
int balance; // stores player's balance
int bettingAmount; // amount being bet, input by player
int guess; // users input for guess
int dice; // stores the random number
char choice;
// main functions
int main()
{
srand(time(0)); // seeds the random number, generates random number
cout << "\n\t\t-=-=-= Dice Roll Game =-=-=-\n";
cout << "\n\nWhat's your name?\n";
getline(cin, playerName);
cout << "\nEnter your starting balance to play with : $";
cin >> balance;
game();
cont();
}
// function declaration
void cont()
{
cin >> choice;
if(choice == 'Y' || choice == 'y')
{
cout << "\n\n";
game();
}
else if (choice == 'N' || choice == 'n')
{
cout << "\n\nThanks for playing.";
}
else
{
cout << "\n\nInvalid input, please type 'y' or 'n'";
cont(); // calls itself (recursive function!!!)
}
}
void game()
{
do
{
cout << "\nYour current balance is $ " << balance << "\n";
cout << "Hey, " << playerName << ", enter amount to bet : $";
cin >> bettingAmount;
if(bettingAmount > balance)
cout << "\nBetting balance can't be more than current balance!\n" << "\nRe-enter bet\n";
} while(bettingAmount > balance);
// Get player's numbers
do
{
cout << "\nA dice will be rolled, guess the side facing up, any number between 1 and 6 : \n";
cin >> guess;
if(guess <= 0 || guess > 6 )
{
cout << "\nYour guess should be between 1 and 6\n" << "Re-enter guess:\n";
}
} while(guess <= 0 || guess > 6);
dice = rand() % 6+1;
diceRoll();
if (dice == guess)
{
cout << "\n\nYou guessed correctly! You won $" << (bettingAmount * 6);
balance = balance + (bettingAmount * 6);
}
else
{
cout << "\n\nYou guessed wrong. You lost $" << bettingAmount << "\n";
balance = balance - bettingAmount;
}
cout << "\n" << playerName << ", you now have a balance of $" << balance << "\n";
if (balance == 0)
{
cout << "You're out of money, game over";
}
cout << "\nDo you want to play again? type y or n : \n";
cont();
}
void diceRoll()
{
cout << "The winning number is " << dice << "\n";
}
Does it only take the first value?
Yes, the >> formatted extraction operator, when called for a single char value, will read the first non-whitespace character, and stop. Everything after it remains unread.
why does 'yy' cause a loop
Because the first "y" gets read, for the reasons explained above. The second "y" remains unread.
This is a very common mistake and a misconception about what >> does. It does not read an entire line of typed input. It only reads a single value after skipping any whitespace that precedes it.
Your program stops until an entire line of input gets typed, followed by Enter, but that's not what >> reads. It only reads what it's asked to read, and everything else that gets typed in remains unread.
So the program continues to execute, until it reaches this part:
cin >> bettingAmount;
At this point the next unread character in the input is y. The >> formatted extraction operator, for an int value like this bettingAmount, requires numerical input (following optional whitespace). But the next character is not numerical. It's the character y.
This results in the formatted >> extraction operator failing. Nothing gets read into bettingAmount. It remains completely unaltered by the >> operator. Because it is declared in global scope it was zero-initialized. So it remains 0.
In addition to the >> extraction operator failing, as part of it failing it sets the input stream to a failed state. When an input stream is in a failed state all subsequent input operation automatically fail without doing anything. And that's why your program ends up in an infinite loop.
Although there is a way to clear the input stream from its failed state this is a clumsy approach. The clean solution is to fix the code that reads input.
If your intent is to stop the program and enter something followed by Enter then that's what std::getline is for. The shown program uses it to read some of its initial input.
The path of least resistance is to simply use std::getline to read all input. Instead of using >> to read a single character use std::getline to read the next line of typed in input, into a std::string, then check the the string's first character and see what it is. Problem solved.
cin >> bettingAmount;
And you want to do the same thing here. Otherwise you'll just run into the same problem: mistyped input will result in a failed input operation, and a major headache.
Why do you need this headache? Just use std::getline to read text into a std::string, construct a std::istringstream from it, then use >> on the std::istringstream, and check its return value to determine whether it failed, or not. That's a simple way to check for invalid input, and if something other than numeric input was typed in here, you have complete freedom on how to handle bad typed in input.

Setting up a loop waiting for user input (C++)

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?

C++ special-value-type loop has to exit when a negative value is entered without using break statement

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)
{
...
}

while statement is unable to read the correct char input

hi i am new to c++ and i dont understand why my while statement doesnt work now. it was working when i tried to do it earlier.
Full code is available at: http://pastebin.com/aeH5fKwh
basically here is the while loop (i excluded all the unnecessary parts, i left the inside of the while loop intact for viewing purpose)
int main()
{
unsigned int seed;
char input;
bool done;
for (int round = 0; round < 5; round++)
{
done = false;
cout << "\nEnter seed: ";
cin >> seed;
cout << "\nRound 1" << endl;
while(!done)
{
cout << "\nDo you wish to draw another card [y][n]: ";
cin >> input;
while (input != 'y' && input != 'n')
{
cout << "Invalid input! Please enter [y][n]!" << endl;
cin >> input;
}
if (input == 'y')
{
dealExtra(playerHand, deck, gameInfo);
cout << "Your cards are ";
printHand(playerHand, gameInfo.playerCardCount);
}
else
done = true;
}
}
cout << endl;
return 0;
}
when i try entering anything that is not 'y', 'n', it will tell me that my input is invalid. But when i try to enter 'y' or 'n', it kinda just ignored it and nothing else happened.. i checked with cout statement and found that it manage to get into the if (input == 'y') statement, but it doesnt seem like it is doing anything else. Everything was fine till 20 minutes ago and i really couldnt figure out whats wrong.
Edit: i ran another test using "cout << '[' << input << ']' << endl;".. it seems like the program is able to get my first input, but then it just hangs there afterwards.. what i get is something like:
Do you wish to draw another card [y][n]: y
[y]
y
y
y
y
I compiled this on linux terminal using g++
if extra codes is needed, i'll edit and add them.. thanks!
When you ask for input from the console, most implementations buffer characters until a newline key is pressed.
After the newline is received, the first character of the buffer is returned. The newline still remains in the buffer as well as any extra characters.
In your case, the second cin >> input statement will read the newline from the buffer.
As an experiment, try entering "frog" and single step through your program. This should illustrate the case of residual characters in the buffer.
Try cin.ignore(1000, '\n') after the first cin >> input. The ignore method will eat up any remaining characters in the buffer until the newline is found.
Make below statements inactive
dealExtra(playerHand, deck, gameInfo);
printHand(playerHand, gameInfo.playerCardCount);
and check if it works, then try making one of the above statements active alternately to find out in which function the flow is getting lost. And so on.
If you feel lazy to run a debugger, and plan to use cout<< statements to find a hanging call, you should flush you cout:
( cout << "I am here and going to hang" ).flush() ;
Otherwise you can't see recent output just because it's still in the output buffer. Try this and you well might see what call hangs your program.
You have an infinite loop inside checkComputerHand:
bool done = false;
while(!done)
{
if(sum == 11 && checkAce == true)
{
computerHand[aceLocation].value = 11;
done = true;
}
if(sum > 11 && checkAce == true)
{
computerHand[aceLocation].value = 1;
done = true;
}
// What if checkAce wasn't true? Infinite loop!
}
Also, the first two lines of newGame do not make any sense:
void newGame(Card playerHand[], Card computerHand[], Statistics &gameInfo)
{
playerHand = '\0';
computerHand = '\0';
// ...
}
Array parameters are silently rewritten by the compiler as pointer parameters. So all you're doing is assigning the null pointer to those local pointers. Probably not what you intended...

cin.get(); doesn't work when I put it in a if statement

I used cin.get() to get the program to pause and wait for user input, and it works fine. The moment I put it in an if statement, it just skips that "wait" period and continues on with the code? How can I solve this. Here is the section that is not working.
do
{
cout << "\n\n\nEnter the number of one of the following and I will explain!\n";
cout << "1.integer 2.boolian 3.floats 4.doubles 5.character";
cout << "\n\n[when you are done type 'done' to continue]\n\n";
cin >> option;
if (option = 1);
{
cout << "\nInteger is the variable abbreviated as 'int' this allows C++ to only";
cout << "\nreadwhole and real numbers \n\n";
cin.get(); //this is the part where it just skips.. it should wait
}
} while (var = 1);
The problem is that cin >> option will extract whatever integer is in the input stream but will leave the following newline character (which is there from hitting enter after typing in the value). When you do cin.get() it is simply extracting that newline character which is already there. Like so many other questions like this, the solution is to empty the input stream after you've extracted into option:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You are also using assignment (=) where you should be comparing for equality (==).