Program doesn't perform looping - c++

bool correct = false;
while (!correct)
{
cout << "Please enter an angle value => ";
cin >> value; //request user to input a value
if(cin.fail())
{
cin.clear();
while(cin.get() != '\n');
correct = false;
}
else
cin.get();
cin.ignore();
correct = true;
}
Here's my problem according to the code above:
After I input a value, the program will pause and I have to press enter again to proceed to next part of the program; how can I avoid it?
Besides, if I enter value like 'abcd', program will not loop to request user to input value again, why is it so?
Instead, it will still proceed and output a value of 0.
I'm still new to these kind of command, just playing and explore them, I appreciate your guides!
edit:
while (!correct)
{
cout << "Please enter an angle value => ";
cin >> value; //request user to input a value
if(cin.fail())
{
cin.clear();
while(cin.get() != '\n');
correct = false;
}
else
{
cin.get();
cin.ignore();
correct = true;
}
}

You set correct=true unconditionally on the very first iteration, and bail out of the loop. Looks like you meant to add a pair of braces around the three statements after else.

Related

Detect blank input on integer type variable?

I am currently working on a text based adventure game as a project for class. I have mostly everything started and working fine. The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room." For the life of me I cannot figure it out. Any help is much appreciated.
Code:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
bool game_play = true;
bool game_start = true;
int room_change;
int room_current = 0;
while (game_play == true) {
if (game_start == true) {
srand((unsigned int)time(NULL));
room_change = rand() % 2 + 1;
game_start = false;
}
else {
for (bool check = false; check == false;) { // Check if input is invalid
cin >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
}
else if (room_change == room_current) {
cout << "You're already in that room.";
}
else {
check = true;
}
}
}
switch (room_change) {
case 1:
cout << "You are in room 1.";
room_current = 1;
break;
case 2:
cout << "You are in room 2.";
room_current = 2;
break;
case 3:
game_play = false;
break;
default:
cout << "That room doesn't exist.";
}
}
return 0;
}
I just ran your code and when you hit enter, it will keep waiting until you enter a number or something invalid such as a character or a string. I did find that if you change your code from
cin >> room_change;
to
cin >> noskipws >> room_change;
when the user inputs a blank, it will cause the cin.fail() to return true and then proceed to print "Choose an existing room."
In your situation, the while loop will keep getting called until we have valid input. The "Choose an existing room" does get repeated because room_change is an integer, so when we hit enter, the '\n' will be left in the buffer. The while loop on the next iteration then reads that '\n' and executes the cin.fail() before letting you input something else. One solution I found is to use more cin.ignore() statements.
for (bool check = false; check == false;) { // Check if input is invalid
cin >> noskipws >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
} else if (room_change == room_current) {
cout << "You're already in that room.";
cin.ignore();
} else {
check = true;
cin.ignore();
}
}
The reason is because we want to get rid of that '\n' so that the cin.fail() does not execute. However, I did find that when you input a character, it will print "Choose an existing room" twice. It will print the first time because a character is not an integer, and a second time because of that '\n'.
The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room."
Using std::getline and then extracting the number from the line using a std::istringstream is a better strategy for that.
std::string line;
std::cout << "Choose an existing room. ";
while ( std::getline(std::cin, line) )
{
// Try to get the room_change using istringstream.
std::istringstream str(line);
if ( str >> room_change )
{
// Successfully read the room.
break;
}
// Problem reading room_change.
// Try again.
std::cout << "Choose an existing room. ";
}
#include <iostream>
using namespace std;
int main(){
int room_change=200;
cout<<"Enter Blank";
cin>>room_change;
if(room_change==NULL){
cout<<"There is NO-THING"<<endl;
}
if(room_change!=NULL){
cout<<"There is something and that is :"<<room_change<<endl;
}
return 0;
}
But a much simpler approach to this would be to use Strings. If this is a Homework of sort and you are limited to Integer variable only. Its much more complicated if you want to detect if an Buffer is empty or not. Regardless of homework limitation, the OS layer input is String based. How can I use cin.get() to detect an empty user input?

How to make the user enter a positive double variable?

I want the user to enter a positive double variable. If they enter anything else, I want the program to loop and continue to ask them to enter a number instead of getting an error and closing. I made an infinite loop with a conditional statement and a break. For some reason if they enter something other than a positive number it infinitely asks for the the radius. Can someone help me with this?
for(;;) {
cout << "Radius: ";
cin >> radius;
if(radius > 0){
break;
}
}
You can simply check the stream state of cin:
double radius;
for(;;) {
cout<<"Radius: ";
if(!(cin>>radius) || radius < 0.0) {
cout << "Invalid input, please enter a positive double value." << endl;
cin.clear();
std::string dummy;
cin >> dummy; // Read the left invalid input
}
else {
break;
}
}
You need to clear the stream's error flags, otherwise you keep looping, since no more other reads are performed when the stream is in a bad state, and radius keeps its value before the loop. You need to do the following (must #include <limits>):
if(!(cin >> radius)) // we didn't read a number, cin has a "bad" state
{
cin.clear(); // clear the error flags
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore the rest
continue;
}

newline character left in the cin.get() buffer

I am using cin.get(input).ignore(INT_MAX, '\n'); in my code. this statement is being called in a while loop to choose an option in a menu.
Although I am using ignore chained with cin.get() for every input I am reading in, sometimes a newline character remains in the cin buffer and I should press an extra 'Enter' to go to the normal process of the while loop for choosing an option.
what should I do to solve this problem?
int Menu::getChoice(int menuNum) // getChoice() returns users menu choice
{
int i = 0;
char input;
while(0 == i) // As long as users choice not valid
{
cout << "Make your choice: ";
cin.get(input).ignore(INT_MAX, '\n');
if (!cin.good())
{
cin.clear();
cin.ignore(INT_MAX, '\n');
}
i = atoi(&input);
if (menuNum == 1)
{
if (i < 1 || i > 2)
{
cout << "Not a valid choice!" << endl;
i = 0;
}
}
}
return i;
}
If I understand correctly, this issue is that sometimes in order for the code to move past cin, and to get the assignment for input, two new line characters are needed. If this is correct, than if you replace:
cin.get(input).ignore(INT_MAX, '\n');
with this:
cin >> input;
the issue will be resolved.

using getline with cin to specify user input

Everytime there is an error with the input type in this function, it automatically sets the value of *_cost to 0. Why is this happening?
void Item::setCost(string input){
float entered;
istringstream stin;
stin.str(input);
if(!(stin >> entered)){
do{
cout << "invalid input" << endl;
stin.clear();
getline(cin, input);
stin.str(input);
*_cost = entered;
}
while(!(stin >> entered));
}
else{
*_cost = entered;
}
}
I use the function in my main function as follows:
istringstream stin;
string input;
cout << "enter cost" << endl;
getline(cin, input);
items[i]->setCost(input);
You are setting *_cost to a value that, because of the if statement, is ALWAYS going to be a necessarily incorrect value.
The *_cost = entered line will ONLY execute when the program is going through its "invalid input" code. The program only prints "invalid input" when entered is not a legal value. Therefore _cost can only be set to an illegal value.
To solve your problem, put the *_cost = entered after the do-while loop.
I'm not sure why you aren't just using std::cin to read the data directly, rather than converting the standard input to an instance of std::string and then to an istringstream.
You need to move the first *_cost = entered out of the do .. while block to become the first statement after it. Having done that, you'll see a further refactor helpful although not required.
while(!(stin >> entered))
{
cout << "invalid input" << endl;
stin.clear();
getline(cin, input);
stin.str(input);
}
*_cost = entered;
while executing *_cost = entered; in your code, entered is invalid.
I have just corrected your code with your original intention
bool Item::setCost(string input) {
bool ret_val = true;
float entered = 0.0;
istringstream stin;
stin.str(input);
while ( !(stin >> entered) ) { // loop till you read a valid input
if ( !stin.rdbuf()->in_avail() ) {
ret_val = false;
break;
}
}
*_cost = entered;
return ret_val;
}
stin.rdbuf()->in_avail() can be used to get the count of available characters ready to be read in from a stringstream, you can use that to check if your stringstream is "empty."
For example if you want to extract an float from a istringstream but you get somthing else (fail condition) and then see if there were any left over characters (ie. numeric) you could check if stin.rdbuf()->in_avail() == 0.

Not handling user input correctly

So, this program I am working on is not handling incorrect user input the way I want it to. The user should only be able to enter a 3-digit number for use later in a HotelRoom object constructor. Unfortunately, my instructor doesn't allow the use of string objects in his class (otherwise, I wouldn't have any problems, I think). Also, I am passing the roomNumBuffer to the constructor to create a const char pointer. I am currently using the iostream, iomanip, string.h, and limits preprocessor directives. The problem occurs after trying to enter too many chars for the roomNumBuffer. The following screenshot shows what happens:
The relevant code for this problem follows:
cout << endl << "Please enter the 3-digit room number: ";
do { //loop to check user input
badInput = false;
cin.width(4);
cin >> roomNumBuffer;
for(int x = 0; x < 3; x++) {
if(!isdigit(roomNumBuffer[x])) { //check all chars entered are digits
badInput = true;
}
}
if(badInput) {
cout << endl << "You did not enter a valid room number. Please try again: ";
}
cin.get(); //Trying to dum- any extra chars the user might enter
} while(badInput);
for(;;) { //Infinite loop broken when correct input obtained
cin.get(); //Same as above
cout << "Please enter the room capacity: ";
if(cin >> roomCap) {
break;
} else {
cout << "Please enter a valid integer" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
for(;;) { //Infinite loop broken when correct input obtained
cout << "Please enter the nightly room rate: ";
if(cin >> roomRt) {
break;
} else {
cout << "Please enter a valid rate" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
Any ideas would be greatly appreciated. Thanks in advance.
Read an integer and test whether it's in the desired range:
int n;
if (!(std::cin >> n && n >= 100 && n < 1000))
{
/* input error! */
}
Although Kerrek SB provide an approach how to address the problem, just to explain what when wrong with your approach: the integer array could successfully be read. The stream was in good state but you didn't reach a space. That is, to use your approach, you'd need to also test that the character following the last digit, i.e., the next character in the stream, is a whitespace of some sort:
if (std::isspace(std::cin.peek())) {
// deal with funny input
}
It seems the error recovery for the first value isn't quite right, though. You probably also want to ignore() all characters until the end of the line.