C++ cin positive integers only - c++

This is my first time on Stackoverflow.
I was making a program to find out MPG for a car. I was wondering how can I make the cin statement only accept positive integers only? and also, if you do enter a invalid input, can you reset it? I am not sure if that makes sense. I didn't have to do this for class. I was just curious on how to do it. Here is the code.
#include <iostream>
using namespace std;
int main()
{
double tank, miles, mpg;
cout << "Hello. This is a program that calculates the MPG ( Miles Per Gallon) for your\n" ;
cout << "vehicle\n" << endl;
cout << "Please enter how many gallons your vehicle can hold\n" << endl;
cin >> tank;
cout << endl;
cout << "Please enter how many miles that have been driven on a full tank\n" <<endl;
cin >> miles;
cout << endl;
mpg = (miles)/(tank);
cout << "Your vehicle recieves " << mpg << " miles per gallon\n" << endl;
system ("pause");
return 0;
}

iostreams are not a toolkit for building a complex UI. Unless you want to write your own rather complex stream to wrap the usual stream, there is no way you are going to get it to either (a) only accept positive integers or (b) interact politely with a user who types in something else.
You should just read lines from cin, and print your own error prompts and such after you look at what you get.

cout << "Hello. This is a program that calculates the MPG ( Miles Per Gallon) for your\n" ;
cout << "vehicle\n" << endl;
do
{
cout << "Please enter how many gallons your vehicle can hold\n" << endl;
cin >> tank;
cout << endl;
} while (tank <= 0 && ((int)tank != tank));
do
{
cout << "Please enter how many miles that have been driven on a full tank\n" <<endl;
cin >> miles;
cout << endl;
} while (miles <= 0 && ((int)miles != miles));
If you do this after running the statements it will rerun them if the answer is 0 or lower or is not an integer. If you make the variables ints instead of doubles then you can remove the "&& ((int)miles == miles)" part of the while statement.

Still, there are a couple of standard ways to do it in a command line environment.
You could trap the cin statement in a loop that doesn't release until a valid input has been entered. This is the "standard" way to validate CLI input, not just signed numbers.
do
{
cout << "\nPlease enter...";
cin >> tank;
}
while (tank < 0)
The condition in the while statement is the place to validate the data. You can also make an if statement to explain why the input is invalid.
The other way is to simply force the value to be positive, by simply going tank = fabs(tank);, which takes the absolute value (i.e. positive) of the tank variable.

So this is my code for an infinite loop
1: So main will call the "Get_number()" function
2: Get number will accept an int from the user
3(A): If int is greater than 0, go into loop
3(B): Else, display to user "Invalid Input" and then call the function
"Get_number()" again creating an infinite loop until the user
enters a value greater than 0
#include <iostream> // Access the input output stream library
#include <fstream> // Access to the fstream library (used to read and write to files)
#include <chrono> // Needed to access "std::chrono_literals"
#include <thread> // Needed to access "namespace std::this_thread"
using std::fstream; // this will allow us to use the fstream (we'll be able to read and write to files)
using std::ios; // needed for iostream (used to be able to tell fstream to read and/or write to a file and that it's reading/writing a binary file)
using std::cout; // need this statment to access cout (to display info to user)
using std::cin; // need this statment to access cin (to gather info from user)
using std::endl; // need this statment to access endl (will end the line)
using namespace std::this_thread; // This will allow me to use "Sleep_For" or "Sleep_Until"
using namespace std::chrono_literals; // This will allow the use of measurements of time such as ns, us, s, h, etc.
//Prototypes***************************************************************************************************
void shellSort(int read[], int readLength); //Making Prototype (Declaring our function) so that compiler knows not to worry about it
void Get_number();
void Write_to_file(int user_input_of_how_many_random_numbers_to_generate); //Making Prototype (Declaring our function) so that compiler knows not to worry about it
void Read_from_file(int user_input_of_how_many_random_numbers_to_generate);//Making Prototype (Declaring our function) so that compiler knows not to worry about it
//*************************************************************************************************************
void main()
{
Get_number();
system("pause>>void"); // will let the console pause untill user presses any button to continue
}
/**************************************************************************************************************
* Purpose: This function will gather a positive integer from the user and use it to generate that many
* random numbers!
*
* Precondition: None
*
*
* Postcondition:
* Would've gathered the number of random numbers the user wanted to generate and then gone into the
* Write_to_file and Read_from_file function
*
**************************************************************************************************************/
void Get_number()
{
int user_input_of_how_many_random_numbers_to_generate = 0; //make variable that will accept the int value the user wants to generate random numbers
cout << "Please Enter A Number Greater Than Zero:" << endl; // displays to user to enter a number greater than zero
cin >> user_input_of_how_many_random_numbers_to_generate; // will accept the value the user inputted and place it in the "user_input_of_how_many_random_numbers_to_generate" variable
system("cls"); // Will clear the screen
if (user_input_of_how_many_random_numbers_to_generate > 0) // if user input is greater than zero, enter this
{
Write_to_file(user_input_of_how_many_random_numbers_to_generate); // will bring up the "Write_to_file" function
Read_from_file(user_input_of_how_many_random_numbers_to_generate); // will bring up the "Read_from_file" function
}
else // else enter this
{
cout << "invalid input!" << endl; // display to user "invalid input"
sleep_for(2s); // system will pause for 2 seconds allowing the user to read the message of "invalid input"
system("cls"); // console will be cleared
Get_number(); // Get_number function will be entered creating an infinate loop untill the user's input is valid!
}
}

Instead of
cin >> miles;
Try
while ( (cin >> miles) < 0 )
cout << "Please enter how many gallons your vehicle can hold\n" << endl;
That will repeat the question until the input is positive. You can do that for the rest of the questions too.
Note that input streams are not intended for input filtering. You have to provide your own logic for that.

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.

For Loops (C++)

Assignment:
The program should ask the user to enter a positive number and display all numbers from 1 to the input value. If the number is not positive, an error message should show up asking the user to re - enter the number.
My specific problem:
For my program, if the user enters an incorrect number and then re - enters a positive number, it does not display all the numbers from 1 to the input value. The program just ends.
#include <iostream>
using namespace std;
int main()
{
int userChoice;
int i = 1;
cout << "Enter a positive integer" << endl;
cin >> userChoice;
if (userChoice > 0)
{
for (i = 1; i <= userChoice; i++)
{
cout << "Loop 1:" << endl;
cout << i << endl;
}
}
else if (userChoice < 0)
cout << "Please re - enter" << endl;
cin >> userChoice;
system("pause");
return 0;
}
You need some sort of loop at the top of your program, that keeps asking for input until the user provides something valid. It looks like a homework assignment, so I will provide pseudo-code, not something exact:
std::cout << "Enter a number:\n";
std::cin >> choice;
while (choice wasn't valid) { // 1
tell the user something went wrong // 2
ask again for input in basically the same way as above // 3
}
// after this, go ahead with your for loop
It is actually possible to avoid the duplication here for step 3, but I worry that might be a little confusing for you, so one duplicated line really isn't such a big problem.
As an aside, you may wish to reconsider your use of what are often considered bad practices: using namespace std; and endl. (Disclaimer - these are opinions, not hard facts).

How to get two inputs from a same input (C++)

Title probably sounds confusing so first I'll show you my code, I made this simple program to get two input values and multiply them, and another thing, but that's not important, It works correctly:
#include <iostream>
using namespace std;
main()
{
int a,b,c,d,e;
char j = 4;
cout << "Welcome to Momentum Calculator\n\n";
cout << "------------------------------\n";
cout << "Please Enter Mass in KG (if the mass in in grams, put \"9999\" and hit enter): \n\n";
cin >> a;
if (a==9999) {
cout << "\nPlease Enter Mass in grams: \n\n";
cin >> d;
}
else {
d = 0;
}
cout << "\nPlease Enter Velocity \n\n";
cin >> e;
if (d == 0)
{
c = (a*e);
}
else {
c = (e*d)/100;
}
cout << "\nMomentum = " << c;
cin.get();
cin.ignore();
while (j == 4)
{
cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
main();
}
}
Now as you can see, my variable is an int (integer) and my problem is If I enter an English letter (a-z) or anything that is not a number will cause it to repeat my program unlimited times at an unlimited speed. I want a string/char to see if my var "a" is a letter or anything but don't know how to. I can do it, however, I want user to input only one time in "a" and mine makes him to enter again. Please Help :)
There is a function called isalpha in ctype library, checks whether your variable is an alphabetic letter so you can do using isalpha function.
Will isdigit or isalpha from standard library help you?
P.S.
1KG contains 1000 grams, so you should divide by 1000, not by 100;
UPDATE:
Seems I understood your question...
You need cin.clear(); before cin.get() and cin.ignore().
Otherwise the these calls won't do anything, as cin is in an error state.
I think you can get a as an String, and see if it contains English letter or not, if it contains, again ask for the input ( you can do it in a while loop ). And when a correct input entered, parse it and find what is it's number.

Writing a first and last name readable over 2 file matching programs

I'm writing a file matching program for a project for school. The idea is that one program allows you to enter info as follows: 1000 (acct number) Jane Doe 54.50 (balance). Then allow you to enter the account number and a transaction amount for the second program to combine and update a new master file.
The programs are working together just fine (the second one takes information from the first, including any transactions and updates the new balance - searching by account number) but the problem I am running into is with the name.
---Wasn't clear here. When I ask for a name and I put in a single string of characters, the program works fine, if I try to put in a full name, like Jane Doe I go into the loop mentioned below.
I've tried char name[20] which puts me into an infinite loop and I have to 'x' out of the program and I've tried assigning first and lastName to string. That worked for the writing but the program that takes the input file oldMaster and the transaction file inTransaction then outputs a new file newMaster, doesn't recognize the name.
I've tried getline also which isn't working for me, probably programmer error.
Should this be done as an array, if that's possible for this? I think I'm getting hung up on the fact that I am editing files. Answers are fine - but I like to figure it out on my own, just looking for a little guidance on where to go from here.
Hopefully this was fairly clear - if not I'll be happy to explain again in a different way. Just frustrated that I'm this close and can't solve it.
Thanks in advance!
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
void createOldMaster()
{
ofstream oldMaster;
int accountNum;
double balance;
char name[15];
oldMaster.open("oldmast.dat", ios::out);
if(!oldMaster)
{
cout << "Unable to open the file." << endl;
exit(1);
} // end if
cout << "Enter the account number (0 to exit)." << endl;
while(true)
{
cout << "Account Number: ";
cin >> accountNum;
if(accountNum == 0)
break;
else
{
\\ This is where it hangs up if I use a first and last name
cout << "\nName: ";
cin >> name;
cout << "\nBalance : " << endl;
cin >> balance;
oldMaster << accountNum << " " << name << " " << balance << endl;
}
}
} //end createOldMaster
void createTransaction()
{
ofstream inTransaction;
int accountNum;
double balance;
inTransaction.open("trans.dat");
if(!inTransaction)
{
cout << "Unable to open the transaction file." << endl;
exit(1);
}
cout << "Enter the account number and balance (0 to exit): " << endl;
while(true)
{
cout << "Account Number: " << endl;
cin >> accountNum;
if(accountNum == 0)
break;
else
{
cout << "Balance: " << endl;
cin >> balance;
inTransaction << accountNum << " " << balance << endl;
}
}
} //end createTransaction
int main()
{
createOldMaster();
createTransaction();
return 0;
}
Your best bet is to use as much of the standard C++ library as you can. Have a reference handy, maybe even a copy of the C++ standard if you're so inclined, and look for shortcuts to make your work easier and your code shorter.
Avoid primitive arrays and primitive strings wherever possible. Instead of primitive arrays try to use std::vector. Instead of primitive strings try to use std::string. Instead of C's FILE* try to use std::ofstream and std::ifstream. If you need to prohibit two accounts with the same account number then choose a C++ container that guarantees unique elements. If you need to find an element in a container try to use a member function of the container for the search, and if that doesn't exist then a standard search function from the standard C++ algorithms.
Reuse and steal mercilessly.

Else statement crashes when i enter a letter for a cin << int value

Alright, I have a question, I veered away from using strings for selection so now I use an integer. When the user enters a number then the game progresses. If they enter a wrong character it SHOULD give the else statement, however if I enter a letter or character the system goes into an endless loop effect then crashes. Is there a way to give the else statement even if the user defines the variable's type.
// action variable;
int c_action:
if (c_action == 1){
// enemy attack and user attack with added effect buffer.
///////////////////////////////////////////////////////
u_attack = userAttack(userAtk, weapons);
enemyHP = enemyHP - u_attack;
cout << " charging at the enemy you do " << u_attack << "damage" << endl;
e_attack = enemyAttack(enemyAtk);
userHP = userHP - e_attack;
cout << "however he lashes back causing you to have " << userHP << "health left " << endl << endl << endl << endl;
//end of ATTACK ACTION
}else{
cout << "invalid actions" << endl;
goto ACTIONS;
}
You haven't shown how you are reading the integer. But in general you want to do something like this:
int answer;
if (cin >> answer)
{
// the user input a valid integer, process it
}
else
{
// the user didn't enter a valid integer
// now you probably want to consume the rest of the input until newline and
// re-prompt the user
}
The problem is that your cin is grabbing the character and then failing, which leaves the character in the input buffer. You need to check whether the cin worked:
if( cin >> k) { ... }
or
cin >>k;
if(!cin.fail()) { ... }
and if it fails, clear the buffer and the fail bit:
cin.clear(); // clears the fail bit
cin.ignore(numeric_limits<streamsize>::max()); // ignore all the characters currently in the stream
EDIT: numeric_limits is found in the limits header file, which you include as per usual:
#include <limits>
Your problem is not with the else-statement, but with your input. If you do something like
cin >> i;
and enter a character, the streams error state is set and any subsequent try to read from the stream will fail unless you reset the error state first.
You should read a string instead and convert the strings contents to integer.