this is my first post here. I am new to c++ (just started last week) and have spent a few hours on this and am stumped.
I am aware that I am probably doing many things wrong in this program, but I assure you all I have tried my best. Validating inputs is beyond the scope of my homework, but I wanted to try it out since just getting inputs and returning them is boring.
Basically, the input validation works for the outer loop, but with the inner loops it will fall through even if invalid.
#include <iostream>
using namespace std;
//Global Variables
int cubeLength = 0;
int cubeWidth = 0;
int cubeHeight = 0;
int cubeSurfaceArea = 0;
int cubeVolume = 0;
bool valid = false;
int main() {
//Ask user for cubeLength and validate input for integer values
do {
cout << "Please enter a numerical value for the length of a cube" <<endl;
cin >> cubeLength;
if (cin.good()) {
valid = true;
//Ask user for cubeWidth and validate input for integer values
do {
cout << "Please enter a numerical value for the width of a cube" <<endl;
cin >> cubeWidth;
if (cin.good()) {
valid = true;
//Ask user for cubeHeight and validate input for integer values
do {
cout << "Please enter a numerical value for the height of a cube" <<endl;
cin >> cubeHeight;
if (cin.good()) {
valid = true;
}
else
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube height. Please try again" << endl;
}
}while (!valid);
}
else
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube width. Please try again" << endl;
}
}while (!valid);
}
else
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube length. Input is not an integer" << endl;
}
} while (!valid);
//Perform calculations for surface area and volume then assign them to their associated variables
if (cubeLength >= 1 && cubeWidth >= 1 && cubeHeight >= 1)
{
valid = true;
cubeSurfaceArea = ((2*(cubeWidth*cubeLength))+(2*(cubeLength*cubeHeight))+(2*(cubeWidth*cubeHeight)));
cubeVolume = (cubeWidth*cubeLength*cubeHeight);
}
else {
cout << "Sorry, one or more cube inputs is invalid. Ending program. Please restart and try again." << endl;
return 0;
}
//Output surface area and volume to user
cout << "Length = " << cubeLength << " Width = " << cubeWidth << " Height = " << cubeHeight << endl;
cout << "The surface area of your cube is " << cubeSurfaceArea << "." << endl;
cout << "The volume of your cube is " << cubeVolume << "." << endl;
//Pause system and end program
return 0;
}
I added the if statement for the calculations at the bottom to stop this from falling all of the way through the program and exit.
I have also checked a lot of similar questions on validating inputs for integers and loops on this site and others, but haven't been able to figure it out. My theory is that i'm either messing up the boolean logic for valid, or using the wrong looping method.
The main problem with the loops is that you are setting valid to true but never to false, so the statement while (!valid) will never evaluate to false.
Another general comment is that the layout of the code has too many nested loops. This can be simplified a lot.
I did not test the code below, but this type of structure is much easier to read - ie doing each input separately, rather than jumbling the all together! :-)
//Ask user for cubeLength and validate input for integer values
valid = true;
do {
cout << "Please enter a numerical value for the length of a cube" <<endl;
cin >> cubeLength;
if (!cin.good()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube length. Input is not an integer" << endl;
}
} while (!valid);
//Ask user for cubeWidth and validate input for integer values
do {
cout << "Please enter a numerical value for the width of a cube" <<endl;
cin >> cubeWidth;
if (!cin.good()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube width. Please try again" << endl;
}
} while (!valid);
//Ask user for cubeHeight and validate input for integer values
do {
cout << "Please enter a numerical value for the width of a cube" <<endl;
cin >> cubeWidth;
if (!cin.good()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube height. Please try again" << endl;
}
}while (!valid);
After the first time you set valid = true, it stays true till the end. You should take it back to false before testing it again.
Thank you to everyone who provided help and feedback:
The issue is painfully obvious to me now, which is the boolean value not being reset at the beginning of the loop after a failed validation on input.
I redid the entire code per suggestions and have a stable program now!:)
#include <iostream>
using namespace std;
//Global Variables
int cubeLength = 0;
int cubeWidth = 0;
int cubeHeight = 0;
int cubeSurfaceArea = 0;
int cubeVolume = 0;
bool valid = true;
char choice;
int main() {
do {
//Ask user for cubeLength and validate input for integer values
do {
valid = true;
cout << "Please enter a numerical value for the length of a cube" <<endl;
cin >> cubeLength;
if (cin.fail()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube length. Input is not an integer" << endl;
}
} while (!valid);
//Ask user for cubeWidth and validate input for integer values
do {
valid = true;
cout << "Please enter a numerical value for the width of a cube" <<endl;
cin >> cubeWidth;
if (cin.fail()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube width. Input is not an integer" << endl;
}
} while (!valid);
//Ask user for cubeHeight and validate input for integer values
do {
valid = true;
cout << "Please enter a numerical value for the height of a cube" <<endl;
cin >> cubeHeight;
if (cin.fail()) {
valid = false;
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Invalid cube height. Input is not an integer" << endl;
}
}while (!valid);
//Perform calculations for surface area and volume then assign them to their associated variables
if (cubeLength >= 1 && cubeWidth >= 1 && cubeHeight >= 1)
{
cubeSurfaceArea = ((2*(cubeWidth*cubeLength))+(2*(cubeLength*cubeHeight))+(2*(cubeWidth*cubeHeight)));
cubeVolume = (cubeWidth*cubeLength*cubeHeight);
}
else {
cout << "Sorry, one or more cube inputs is invalid. Ending program. Please restart and try again." << endl;
return 0;
}
//Output surface area and volume to user
cout << "Length = " << cubeLength << " Width = " << cubeWidth << " Height = " << cubeHeight << endl;
cout << "The surface area of your cube is " << cubeSurfaceArea << "." << endl;
cout << "The volume of your cube is " << cubeVolume << "." << endl;
cout << "Would you like to try again? (y/n)" << endl;
cin >> choice;
} while (choice != 'n');
//Pause system and end program
return 0;
}
Related
I have this code that asks for a number input and stores it in a variable. I'm trying to do validation on the input but it's behaving weirdly.
#include <iostream>
using namespace std;
float coursework_mark;
float exam_mark;
float module_mark;
int main() {
//COURSEWORK INPUT WITH VALIDATION
cout << "Please enter your coursework mark: ";
while(!(cin >> coursework_mark)){
cin.clear();
cin.ignore(1000, '\n');
cout << "Invalid data type, please enter valid coursework mark: ";
}
while (coursework_mark < 0 || coursework_mark > 100) {
cout << "Out of range, please enter valid coursework mark: ";
cin >> coursework_mark;
}
//EXAM MARK INPUT WITH VALIDATION
cout << "Please enter your exam mark: ";
while(!(cin >> exam_mark)) {
cin.clear();
cin.ignore(1000, '\n');
cout << "Invalid data type, please enter valid exam mark: ";
}
while (exam_mark < 0 || exam_mark > 100) {
cout << "Out of range, please enter valid exam mark: ";
cin >> exam_mark;
}
//Coursework capping
if (coursework_mark > exam_mark * 2) { coursework_mark = exam_mark * 2;}
//Calculate Module mark
module_mark = (coursework_mark* 0.4) + (exam_mark* 0.6);
//Output results
cout << coursework_mark << endl;
cout << "Your module mark is " << module_mark << endl;
if (module_mark >= 50) {
cout << "Congratulations you have passed!" << endl;
} else if (module_mark < 50) {
cout << "Unfortunately, you have not passed" << endl;
}
}
If user inputs '45kuefggf' the number 45 gets stored as the coursework mark and the code hits the line cout << "Out of range, please enter valid exam mark: ";. I have no idea why it's doing this, how do I make it so that it check if the user input a valid data type?
Instead of
while(!(cin >> coursework_mark)){
you should use std::getline
std::getline(std::cin, coursework_mark);
https://en.cppreference.com/w/cpp/string/basic_string/getline
bool has_only_digits(string s){
return s.find_first_not_of( "0123456789" ) == string::npos;}
This method is the simplest way I found to check if a string contains a number. So if it returns true the string has only digits else it contains more than just digits.
If the statement is false you can then clear the cin like you have done above.
I made this for an assignment but even if I enter a valid input from the desired range I still get prompted. This is happening to both input prompts. I suspect the problem is in the while blocks of the setupGame function.
#include <iostream>
using namespace std;
bool setupGame(int numberRef, int triesRef);
int main(){
cout<<"hello world";
setupGame(4,4);
cout<<"enough";
}
//SETUP GAME FUNCTION
bool setupGame(int numberRef, int triesRef) {
do {
cout << "ENTER A NUMBER BETWEEN 1 and 100" << endl;
cin >> numberRef;
cin.clear();
//your code here
cout << "You entered: " << numberRef << endl;
if (numberRef==-1) {
cout << "You do not want to set a number " << endl;
cout << "so you stopped the program" << endl;
}
else if(numberRef >=1 && numberRef <=100)
do {
cout << "ENTER TRIES BETWEEN 3 and 7" << endl;
cin >> triesRef;
cin.clear();
//cin.ignore( '\n');
cout<< "You entered: "<< triesRef<< endl;
if (triesRef==-1) {
cout << "You do not want to set tries. ";
cout << "so you stopped the program" << endl;
} else if(triesRef <= 3 && triesRef >= 7){
cout<<"Number of tries should be between 3 and 7";
}
}
while(numberRef >=1 && numberRef <=100);{
return true;
}
}
while(triesRef >= 3 && triesRef <= 7);{
return true;
} }
You're tangling yourself up with these nested loops. Your prompt keeps printing because the while loop:
while(numberRef >=1 && numberRef <=100)
is going to keep repeating it's preceding do block until you enter a value less than 1 or greater than 100, same goes for the last while loop as well.
I assume you're using cin.clear() to flush the previous input, if you are then stop it, that is not the purpose of cin.clear(). It's instead use to clear the error state of cin. Please thoroughly read up on it here.
Below is the code to achieve what you want, please observe how I implemented the while loops after each cin prompt to ensure that a valid character is entered.
#include <iostream>
#include <fstream>
using namespace std;
bool setupGame(int numberRef, int triesRef);
int main(){
cout<<"hello world";
setupGame(4,4);
cout<<"enough";
}
//SETUP GAME FUNCTION
bool setupGame(int numberRef, int triesRef) {
cout << "ENTER A NUMBER BETWEEN 1 and 100" << endl;
cin >> numberRef;
while((numberRef < 1 || numberRef > 100 || cin.fail()) && numberRef != -1) {
cin.clear(); // Used to clear error state of cin
cin.ignore(); // Might want to ignore the whole line
cout<<"Number should be between 1 and 100, or -1 , please try again: ";
cin>>numberRef;
}
cout << "You entered: " << numberRef << endl;
if (numberRef==-1) {
cout << "You do not want to set a number " << endl;
cout << "so you stopped the program" << endl;
}
if(numberRef >=1 && numberRef <=100) {
cout << "ENTER TRIES BETWEEN 3 and 7" << endl;
cin >> triesRef;
while(triesRef < 3 || triesRef > 7 || cin.fail()) {
cin.clear(); // Used to clear error state of cin
cin.ignore(); // Might want to ignore the whole line
cout<<"Tries should be between 3 and 7 , please try again: ";
cin>>triesRef;
}
cout<< "You entered: "<< triesRef<< endl;
if (triesRef==-1) {
cout << "You do not want to set tries. ";
cout << "so you stopped the program" << endl;
return false;
}
}
}
When a user enters spaces in between digits to create a reference string it throws everything off and will even carry numbers over to the next cin. If however they have letters in between and no spaces it works fine. The assignment was for a page replacement sim.
Code (this is only the part of the code that should effect my problem):
void main()
{
bool again = false;
bool reuse = false;
bool valid;
int use;
int refLength;
vector<int> ref(0);
vector<frame> frames(0);
string refString;
string user;
//ask how long the user wants the ref string to be
do{
valid = false;
while (!valid&&!reuse)//take choice of ref string
{
cout << "How long do you wish the reference string to be? ";
if (!(cin >> refLength))
{
cin.clear();//.clear and .ignore keep cin from errors and forced infinite loop repeating following cout
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "The length must be enter as an integer value between ";
valid = false;
}
else
{
cout << "You have chosen to have a Ref string of " << refLength << " length " << endl;
valid = true;
}
}
valid = false;
while (!valid&&!reuse)
{
cout << "Do you want to enter a ref string or randomly generate one" << endl;
cout << "of your chosen length? Enter 1 to generate and 2 to input the string ";
if (!(cin >> use) | (use<0 || use>2))
{
cin.clear();//.clear and .ignore keep cin from errors and forced infinite loop repeating following cout
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You must enter an integer between 1 and 2";
}
else
{
valid = true;
if (use == 1)
{
make(ref, refLength);
}
else
{
cout << "please enter a ref string of chosen length entering" << endl;
cout << "fewer digits will cause 0's to be added. Entering more" << endl;
cout << "will cause those past the chosen length to be dropped " << endl;
cout << "any letters will be ignored but spaces throw things off" << endl;
cout << "Also all entries must be single digit integers (0-9) " << endl;
cin >> refString;
make(ref, refLength, refString);
}
use = 0;
}
}
cout << endl;
/*for(int i=0;i<ref.size();i++)
{
cout<<ref[i]<<" ";
}*/
valid = false;
while (!valid)
{
cin.clear();
//errors ********************************************88
cout << "How many frames do you want (1-7) ";
if (!(cin >> use) | (use<0 || use>7))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You must enter an integer between 1 and 7 ";
valid = false;
}
else
{
valid = true;
setUpFrames(use, frames);
use = 0;
}
}
valid = false;
while (!valid)
{
cout << "Enter 1 for FIFO or 2 for LRU pageRep algo or 3 for Optimal";
if (!(cin >> use) | (use<0 || use>3))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Must be int between 1 and 3";
}
else if (use == 1)
{
cout << endl << "# of Page Faults ";
cout << FIFO(ref, frames);
valid = true;
}
else if (use == 2)
{
cout << endl << "# of Page Faults ";
cout << LRU(ref, frames);
valid = true;
}
else
{
cout << endl << "# of Page Faults ";
cout << Optimal(ref, frames);
valid = true;
}
}
cout << endl;
cout << "do you want to try again ? Enter y for yes anything else for no" << endl;
cin >> user;
if (user == "y")
{
again = true;
cout << "do you want to use the same reference string? y for yes anything else for no" << endl;
cin >> user;
if (user == "y")
{
reuse = true;
}
else
{
reuse = false;
}
}
else
{
again = false;
}
} while (again);
}
If you want cin/cout interaction word/line by word/line use getline, otherwise confusion will arise.
In the below code, I'm running into an error when I try to get the user to input their name. My program just skips it over and goes right over to making the function calls without allowing the user to enter their name. Despite the error, my program is compiling. I'm not sure what's going wrong as I wrote that part based off other examples I found on here. Any suggestions?
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
char showMenu();
void getLottoPicks(int[]);
void genWinNums(int[]);
bool noDuplicates(int[]);
const int SIZE = 7;
int main()
{
int userTicket[SIZE] = {0};
int winningNums[SIZE] = {0};
char choice;
string name;
srand(time(NULL));
do
{
choice = showMenu();
if (choice == '1')
{
cout << "Please enter your name: " << endl;
getline(cin, name);
getLottoPicks(userTicket);
genWinNums(winningNums);
for (int i = 0; i < SIZE; i++)
cout << winningNums[i];
}
} while (choice != 'Q' && choice != 'q');
system("PAUSE");
return 0;
}
Added the code for showMenu:
char showMenu()
{
char choice;
cout << "LITTLETON CITY LOTTO MODEL:" << endl;
cout << "---------------------------" << endl;
cout << "1) Play Lotto" << endl;
cout << "Q) Quit Program" << endl;
cout << "Please make a selection: " << endl;
cin >> choice;
return choice;
}
And getLottoPicks (this part is very wrong and I'm still working on it):
void getLottoPicks(int numbers[])
{
cout << "Please enter your 7 lotto number picks between 1 and 40: " << endl;
for (int i = 0; i < SIZE; i++)
{
cout << "Selection #" << i + 1 << endl;
cin >> numbers[i];
if (numbers[i] < 1 || numbers[i] > 40)
{
cout << "Please choose a number between 1 and 40: " << endl;
cin >> numbers[i];
}
if (noDuplicates(numbers) == false)
{
do
{
cout << "You already picked this number. Please enter a different number: " << endl;
cin >> numbers[i];
noDuplicates(numbers);
} while (noDuplicates(numbers) == false);
}
}
}
After doing cin >> choice; inside char showMenu(), if a user inputs 1[ENTER], the char consumes 1 character from cin, and the newline stays inside the stream. Then, when the program gets to getline(cin, name);, it notices that there's still something inside cin, and reads it. It's a newline character, so getline gets it and returns. That's why the program is behaving the way it is.
In order to fix it - add cin.ignore(); inside char showMenu(), right after you read the input. cin.ignore() ignores the next character - in our case, the newline char.
And a word of advice - try not to mix getline with operator >>. They work in a slightly different way, and can get you into trouble! Or, at least remember to always ignore() after you get anything from std::cin. It may save you a lot of work.
This fixes the code:
char showMenu()
{
char choice;
cout << "LITTLETON CITY LOTTO MODEL:" << endl;
cout << "---------------------------" << endl;
cout << "1) Play Lotto" << endl;
cout << "Q) Quit Program" << endl;
cout << "Please make a selection: " << endl;
cin >> choice;
cin.ignore();
return choice;
}
from looking at code showMenu function has problem. and it's not returning asccii equivalent of '1' that is: 31 integer. try printing value returned by showmenu. you will get that
UPDATE:
It is because cin in delimited by ' '(whitespace) and getline by '\n' character, so when enter name and press enter cin in showmenu will consume whole string except '\n' from istream and that is read by getline. to see this when it ask for choice enter string like 1 myname (1 whitespace myname)and press ENTER will display name. now cin will read 1 in choice and myname in name by getline.
bool showMenu(romanType roman){
cout << endl;
cout << "Just enter a number to choose an option" << endl;
cout << "1: Print the Roman Numeral" << endl;
cout << "2: Print the decimal value" << endl;
cout << "3: Enter a new Roman Numeral" << endl;
cout << "4: Quit the program" << endl;
cout << endl;
while (true) {
cout << "Your choice:" << endl;
int input;
cin >> input;
if (input == 1) {
cout << roman.getRomanString() << endl;
} else if(input ==2) {
cout << roman.getDecimalValue() << endl;
} else if(input == 3) {
return true;
} else if(input == 4) {
return false;
} else {
cout << "Invalid selection, please make a valid selection." << endl;
}
}
}
Alight, so by and large this works fine, I'm just having one small problem with my final else statement. As long as the user has entered a type of int, the loop does what it is supposed to, however if any kind of string is entered (i.e. 45r, rts, 3e5) the loop stops taking user input and just spirals infinitely, cout(ing) Invalid selection... and Your choice... over and over again. I think I need to use .ignore() to drop the \n in the case of a string, but I'm not sure of how to do that. Am I on the right track?
Yes, you're on the right track.
cin >> input tries to extract an integer. If this fails no symbols are extracted from cin and the failbit is set. In this case the extraction won't work anymore. You have to ignore the rest of the user input and clear the error bits:
} else {
cout << "Invalid selection, please make a valid selection." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
// numeric_limits<streamsize>::max() returns the maximum size a stream can have,
// see also http://www.cplusplus.com/reference/std/limits/numeric_limits/
}
See also Why is this cin reading jammed?.