Why is my nested while-loop looping infinitely? - c++

I am having trouble getting this nested while-loop to function how I want it to.
#include <iostream>
#include <math.h>
double time_to_ground(double);
int main() {
std::cout.precision(4);
bool go = 1;
double height{};
while (go) {
std::cout << "Please enter the height of the building in meters.\n";
std::cin >> height;
while (height < 0) {
std::cout << "\nPlease enter a positive number.\n";
std::cin >> height;
}
double time = time_to_ground(height);
std::cout << "It will take " << time << " seconds for the ball to reach the ground to reach the ground.\n";
std::cout << "Go again?\n0) no\n1) yes\n";
std::cin >> go;
//This loop breaks the code
while (!((go == 0) || (go == 1))) {
std::cout << "Enter either:\n0) no\n1) yes\n";
std::cin >> go;
}
}
return 0;
}
double time_to_ground(double height) {
return sqrt(2 * height / 9.81);
}
The idea is simply just to make sure the user only inputs a 0 or 1. It works fine if I put a 0 or 1, However when I run the code and input say, a 6, I get stuck in an infinite loop!
Thanks in advance!

You have declared go as a bool but you are trying to read it as an integer.
Just change bool go = 1; to int go = 1;
Trying to read an integer input that is not 0 or 1 into a boolean variable fails and once cin has failed all input using cin will fail until you clear the error. That's why you get an infinite loop.
An alternative way of writing the loop is to check for the input error directly. You can keep the go variable as bool and write this
while (!(std::cin >> go))
{
std::cin.clear(); // clear the cin error
std::cout << "Enter either:\n0) no\n1) yes\n";
}
This works because std::cin >> go will return false if the input fails. Notice that I clear the error once it has occurred.

An alternate solution to this would be to keep bool go = 1; and then replace:
while (!((go == 0) || (go == 1))) {
std::cout << "Enter either:\n0) no\n1) yes\n";
std::cin >> go;
}
with:
while (std::cin.fail())
{
std::cin.clear();
std::cout << "Enter either:\n0) no\n1) yes\n";
std::cin >> go;
}
std::cin.fail() returns true if the last std::cin input failed. But will return false otherwise.
std::cin.clear() clears the error flag on std::cin.

use int data type in your main function
int go = 1;
instead of bool
bool go = 1;
bool can not handle values other than 0,1
it will work.

Related

cin buffer Issues in C++

I'm learning C++, so I don't fully understand what's going on with my code here, but from what I've been able to glean, it seems like it could be some kind of buffer issue.
#include <stdio.h>
#include <vector>
#include <iostream>
#include <typeinfo>
using namespace std;
bool stopRun = true;
int height, average, total, count;
vector <int> heights;
int main ()
{
while (stopRun)
{
cout << "Enter a height, or 'end' to quit: ";
cin >> height;
if (typeid(height).name() == "i")
{
heights.push_back(height);
cout << heights[0];
count++;
}
else if (typeid(height).name() == "i")
{
cout << "\nPlease enter an integer: ";
continue;
}
if (count == 5)
{
stopRun = false;
}
}
for (int i = 0; i < heights.size(); i++)
{
total += heights[i];
cout << "\nTotal: " << total;
}
return 0;
}
For some reason, this code will continuously output: "Enter a height, or 'end' to quit: ". In an earlier version, it would output: "Enter a height, or 'end' to quit: Please enter an integer: ".
What I think is going on is that my "cin >> height;" line is pulling in the output from "Please enter an integer: " and treating it as my input, which identifies it as not being of type integer, which starts the infinite loop.
How do I clear the input buffer so that it doesn't bring in cout statements? Or is that even the issue I'm experiencing here?
Thanks in advance!
I suggest to catch the string. If string is not "end" then convert to number inside try/catch
you can use this function at the start of your program fflush(stdin). It will clear your input buffer.
You are attempting to read an int and a string in the same line of code. I suggest you use getline() to read the input and try to convert the string to int.
std::string input;
while (heights.size() != 5) {
cout << "Enter a height, or 'end' to quit: ";
if (std::getline(cin, input)) {
if (input == "end") break;
try {
heights.push_back(std::stoi(input));
}
catch (std::invalid_argument e) {
cout << "\nPlease enter an integer: ";
}
}
}
if (string(typeid(height).name()) == "i")
What you had wrong was the comparison of a pointer and string. Since typeid(height).name() returns a pointer to a c-string with the name for the object.

Validating binary input in C++

Hi i'm attempting to validate a user input looking for an input of either 1 or 0. The string validating part seems to work fine but any integer based input has the console window accepting the input but not jumping over the if statement, returning the input (maxItems). Here is the code :
int RollingStats::GetOption()
{
int maxItems;
std::cout << "Please enter either to store data individually (0) or as a range(1)" << std::endl;
std::cin >> maxItems;
if ((!(std::cin >> maxItems) && maxItems != 0) | (!(std::cin >> maxItems) && maxItems != 1))
{
std::cin.clear();
std::cin.ignore(100, '\n');
std::cout << "Please enter an input of either 0 or 1" << std::endl;
GetOption();
}
return maxItems;
}
Any help would be appreciated.
Some issues in the code:
Using cin thrice (once before if and twice in the if condition) would require the user to input thrice
Using logical OR (||) instead of bit-wise or (|) in your if condition check.
Not checking if the input is an integer
You can do something like this instead:
int RollingStats::GetOption()
{
int maxItems;
std::cout << "Please enter either to store data individually (0) or as a range(1)" << std::endl;
std::cin >> maxItems;
if(!std::cin.good() || maxItems != 0 && maxItems != 1)
{
std::cin.clear();
std::cin.ignore(100, '\n');
std::cout << "Please enter an input of either 0 or 1" << std::endl;
maxItems = GetOption();
}
return maxItems;
}

loop repeats without prompting the user again?

I have this snippets of code from my original long program, and as much as it looks simple, it doesn't work correctly! I am brand-new to c++ language, but I know in Java that would be the way to do it (Regardless of the syntax).
Simply put, this should ask the user for an input to answer the following multiplication (5*5), however, it should also check if the user entered a wrong input (not number), keep asking the user again and again... Somehow, it keeps running forever without taking a new input!!
I hope to get, not only an answer, but also a reason for such an error!
int main() {
int userAnswer;
bool isValidAnswer = true;
cout << 5 << " * " << 5 << " = ";
cin >> userAnswer;
cin.ignore();
do {
if (cin.fail()) { //user input is not an integer
cout << "Your answer is not valid! Please enter only a natural number: ";
cin >> userAnswer;
cin.ignore();
} else {
isValidAnswer = false;
}
} while (isValidAnswer);
return 0;
}
Well you need to clear the error state before accepting new input. Call cin.clear() then cin.ignore() before trying to read input again.
I would do something like.
cout << "Enter a number: ";
cin >> number;
while(cin.fail())
{
cin.clear();
cin.ignore(1000, '\n'); //some large number of character will stop at new line
cout << "Bad Number Try Again: ";
cin >> number;
}
First, cin.fail() is not going to adequately check if your answer is a natural number or not with the type set to int (could also be negative).
Second, your boolean isValidAnswer is really checking if it's is an invalid answer.
Third (and most importantly), as another answer suggests, you should put in cin.clear() to clear the failure state, and then followed by cin.ignore(), which will remove the failed string from cin.
Fourth, cin will only check if an int exists somewhere in the string. You'll need to perform your own string comparison to determine if the entire input is a int (see answer below, based on this answer).
Updated:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
bool isNum(string line)
{
char* p;
strtol(line.c_str(), &p, 10);
return *p == 0;
}
int main() {
int userAnswer;
string input;
bool isInvalidAnswer = true;
cout << 5 << " * " << 5 << " = ";
while (isInvalidAnswer) {
if (!(cin >> input) || !isNum(input)) {
cout << "Answer is not a number! Please try again:\n";
cin.clear();
cin.ignore();
}
else {
userAnswer = atoi(input.c_str());
if (userAnswer < 0) { //user input is not an integer
cout << "Answer is not a natural number! Please try again:\n";
} else {
isInvalidAnswer = false;
}
}
}
cout << "Question answered!\n";
return 0;
}

CIN within certain range

I am trying to make a cin where the user can only enter 0 to 1. If the user doesnt enter those numbers then he should get an error saying "Please enter within the range of 0 to 1."
But its not working.
What am i doing wrong?
int alphaval = -1;
do
{
std::cout << "Enter Alpha between [0, 1]: ";
while (!(std::cin >> alphaval)) // while the input is invalid
{
std::cin.clear(); // clear the fail bit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the invalid entry
std::cout << "Invalid Entry! Please Enter a valid value: ";
}
}
while (0 > alphaval || 1 < alphaval);
Alpha = alphaval;
Try this:
int alphaval;
cout << "Enter a number between 0 and 1: ";
cin >> alphaval;
while (alphaval < 0 || alphaval > 1)
{
cout << "Invalid entry! Please enter a valid value: ";
cin >> alphaval;
}
If you want to trap empty lines I'd use std::getline and then parse the string to see if the input is valid.
Something like this:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
int alphaval = -1;
for(;;)
{
std::cout << "Enter Alpha between [0, 1]: ";
std::string line;
std::getline(std::cin, line);
if(!line.empty())
{
std::stringstream s(line);
//If an int was parsed, the stream is now empty, and it fits the range break out of the loop.
if(s >> alphaval && s.eof() && (alphaval >= 0 && alphaval <= 1))
{
break;
}
}
std::cout << "Invalid Entry!\n";
}
std::cout << "Alpha = " << alphaval << "\n";
return 0;
}
If you want a different prompt on error then I'd put the initial prompt outside the loop and change the inner prompt to what you prefer.
Week one of C++, starting with Peggy Fisher's Learning C++ on Lynda.com.
This is what I came up with. Love to receive feedback.
int GetIntFromRange(int lower, int upper){
//variable that we'll assign input to
int input;
//clear any previous inputs so that we don't take anything from previous lines
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//First error catch. If it's not an integer, don't even let it get to bounds control
while(!(cin>>input)) {
cout << "Wrong Input Type. Please try again.\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
//Bounds control
while(input < lower || input > upper) {
cout << "Out of Range. Re-enter option: ";
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//Second error catch. If out of range integer was entered, and then a non-integer this second one shall catch it
while(!(cin>>input)) {
cout << "Wrong Input Type. Please try again.\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
//return the cin input
return input;
}
As the exercise was to order Hamburgers, this is how I ask for the amount:
int main(){
amount=GetIntFromRange(0,20);
}

Integer validation for input

I tried to prompt user for input and do the validation. For example, my program must take in 3 user inputs. Once it hits non-integer, it will print error message and prompt for input again. Here is how my program going to be look like when running :
Enter number: a
Wrong input
Enter number: 1
Enter number: b
Wrong input
Enter number: 2
Enter number: 3
Numbers entered are 1,2,3
And here is my code:
double read_input()
{
double input;
bool valid = true;
cout << "Enter number: " ;
while(valid){
cin >> input;
if(cin.fail())
{
valid = false;
}
}
return input;
}
My main method:
int main()
{
double x = read_input();
double y = read_input();
double z = read_input();
}
When my first input is non-integer, the program just exits by itself. It does not ask for prompting again. How could I fixed it? Or am I supposed to use a do while loop since I asking for user input.
Thanks in advance.
When the reading fails, you set valid to false, so the condition in the while loop is false and the program returns input (which is not initialized, by the way).
You also have to empty the buffer before using it again, something like:
#include <iostream>
#include <limits>
using namespace std;
double read_input()
{
double input = -1;
bool valid= false;
do
{
cout << "Enter a number: " << flush;
cin >> input;
if (cin.good())
{
//everything went well, we'll get out of the loop and return the value
valid = true;
}
else
{
//something went wrong, we reset the buffer's state to good
cin.clear();
//and empty it
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Invalid input; please re-enter." << endl;
}
} while (!valid);
return (input);
}
Your question did get myself into other issues like clearing the cin on fail() --
double read_input()
{
double input;
int count = 0;
bool valid = true;
while(count != 3) {
cout << "Enter number: " ;
//cin.ignore();
cin >> input;
if(cin.fail())
{
cout << "Wrong Input" <<endl;
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else
count++;
}
return input;
}
The problem is in the while condition
bool valid = true;
while(valid){
You loop until you get a non valid input, this absolutly not what you want! loop condition should be like this
bool valid = false;
while(! valid){ // repeat as long as the input is not valid
Here is a modified version of your read_double
double read_input()
{
double input;
bool valid = false;
while(! valid){ // repeat as long as the input is not valid
cout << "Enter number: " ;
cin >> input;
if(cin.fail())
{
cout << "Wrong input" << endl;
// clear error flags
cin.clear();
// Wrong input remains on the stream, so you need to get rid of it
cin.ignore(INT_MAX, '\n');
}
else
{
valid = true;
}
}
return input;
}
And in your main you need to ask for as may doubles as you want, for example
int main()
{
double d1 = read_input();
double d2 = read_input();
double d3 = read_input();
cout << "Numbers entered are: " << d1 << ", " << d2 << ", " << d3 << endl;
return 0;
}
You may also want to have a loop where you call read_double() and save the returned values in an array.