decision making and recursive functions - c++

i want to make a calculator without the GUI, but i have some problem like this
cout<<"calculator : ";cin>>userAnswer;
if(userAnswer=='yes'){
//procces
} else if(userAnswer=='no'){
//exit
} else{
//here is the problem
}
when the user enters an input that aside from yes or no I want the program to ask the user again whether the user wants to use the calculator again.
but I don't know how. I have used a recursive function, but the number of times a user enters a wrong input, so the program will ask "does the user want to use a calculator?"

You can do it like this -
while (true) {
cout<<"calculator : ";
while(true) {
cin>>userAnswer;
if(userAnswer=='yes'){
//procces
} else if(userAnswer=='no'){
//exit
} else {
break;
}
}
cout<<"Do you want to use a calculator? ";
string feedback;
cin >> feedback;
if ( feedback == "yes") {
continue;
} else {
break;
}
}

You want something like this I guess,
string userAnswer;
cout<<"calculator : ";
cin>>userAnswer;
while(true)
{
while(true)
{
cout<<"\ndoes the user want to use the calculator : ";
cin>>userAnswer;
if(userAnswer=="yes" || userAnswer=="no")
break;
else
cout<<"only yes or no input is valid\n";
}
if(choice=="no")
{
cout<<"\nExiting from the calculator\n";
break;
}
cout<<"Enter your choice: \n";
cout<<"1-Addition\n";
cout<<"2-Subtraction\n";
// your stuff below
}

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?

C++: Telling user to input A, B, or C but what if they enter a different character?

As the title suggests, I have a working program for when a user inputs A B or C. My professor has said that we have not gone over repetition yet so we just need to put in a line of code that returns something like "Please enter either A B or C" when the user enters any other character but I am having trouble figuring out how to do this. Any help will be very appreciated. I'll post a file of the code I have now.
https://docs.google.com/document/d/1EVxLPtOsBbdmCCt0LwUDYkqgySg8bSm3w_d_CAcGW6g/edit?usp=sharing
Here is a common stencil for processing menus:
bool invalid_selection = true;
while (invalid_selection)
{
// Output the menu with choices
// ...
char choice;
std::cin >> choice;
choice = std::toupper(choice);
switch (choice)
{
case 'A':
do_something;
break;
// ... other choices ...
default:
std::cout << "Invalid choice.";
}
if (choice == quit_character)
{
break; // exit out of the loop
}
}
There are many other alternatives. For example, one is a do-while loop.
If you don't know about switch, use your if-else-if ladder. The final else clause is equivalent to the default case.
EDIT: It'd be even better to use a std::string as a buffer to prevent receiving multiple errors from this if the user inputs more than one char.
The best way to handle this would probably be a simple do... while nested switch statement:
#include <string>
bool repeat = true;
do {
std::string buffer;
cout << "Which plan do you want to use?" << endl;
cin >> buffer;
// check if the user entered only one character
if (buffer.length() > 1) {
cout << "Invalid Input" << endl;
continue;
}
plan = buffer[0];
switch(plan) {
case 'A':
// do things
repeat = false;
break;
case 'B':
// do things
repeat = false;
break;
case 'C':
// do things
repeat = false;
break;
default:
cout << "Invalid input, please try again." << endl;
break;
} while (repeat);
This keeps asking the user for which plan they want to use, until you receive valid input.
Note: OP did not want a complete refactoring of his code. So this is the minimal-intervention solution.
Edit your if statements to:
if(plan=='A'){
//...
} else if(plan=='B'){
//...
} else if(plan=='C'){
//...
} else {
//handle the error here.
cout << "Wrong input" << endl;
}

C++, program outputs invalid input but continues through loop

I am trying to write a program which calculates the cost of a call based on the time the call was made, the day of the week and length of call. It has to be all call-by-value functions and output a option to repeat the program.
My problem is when I enter a invalid input for time such as a:37, it outputs invalid input but continues to the day input instead of returning to time entry. I am a new programmer and have tried everything I can think of to fix it but it either gets stuck in a infinite loop of exits the entire program.
Thanks in advance for any help!
#include <iostream>
using namespace std;
bool validateUserInputTime(int,char,int);
bool validateUserInputDay(string);
bool validateUserInputCallLength(int);
double calculateTotalCost(int,int,string,int);
string days[]={"Mo" , "Tu" , "We" , "Th" , "Fr" , "Sa" , "Su"};
float cost,fcost;
int main()
{
int hour;
int min;
int time;
char colon;
char answer = 'y';
string day;
string s;
bool result;
while(answer =='y')
{
cout<<"Enter the time the call starts in 24-hour rotation: "<<endl;
cin>>hour>>colon>>min;
result=validateUserInputTime(hour,colon,min);
if(cin.fail())
{
cout << "Invalid time input."<<endl;
cout<<"Please try again."<<endl<<endl<<endl;
cin.clear();
}
day=validateUserInputDay(s);
if(cin.good())
{
cout<<"Enter the first two letters of the day of the week:";
cin>>day;
}
cout<<"Enter the length of the call in minutes:"<<endl;
cin>>time;
result=validateUserInputCallLength(time);
if(result==0)
{
cout<<"Invalid minute Input."<<endl;
cout<<"Please try again."<<endl<<endl<<endl;
continue;
}
fcost= calculateTotalCost(hour,min,day,time);
cout<<"Cost of the call: $" << fcost<<endl;
cout<<"Do you want to repeat the program?";
cin>>answer;
}
return 0;
}
bool validateUserInputTime(int hour1,char ch,int min1)
{
if (cin.fail())
{
cout << "Invalid time input."<<endl;
cout<<"Please try again."<<endl<<endl<<endl;
cin.clear();
}
if(hour1 < 0)
{
return false;
}
if(min1 < 0)
{
return false;
}
if(ch!=':')
{
return false;
}
else
return true;
}
bool validateUserInputDay(string s)
{
int next=0;
for(int i = 0; i < 7; i++)
{
if(days[i] == s){
next=1;
}
if(cin.fail())
{
cout<<"Invalid day inpuT."<<endl;
cin.clear();
}
}
if(next==1)
{
return true;
}
else
{
return false;
}
}
bool validateUserInputCallLength(int time2)
{
if(time2<0)
{
return false;
}
else
{
return true;
}
}
double calculateTotalCost(int hour3,int min3,string d,int time3)
{
if((d=="Sa")||(d=="Su"))
{
cost=0.15*time3;
}
else
{
if((hour3>=8)&&(min3<18))
{
cost=0.40*time3;
}
else
cost=0.25*time3;
}
return cost;
}
Try using a loop. The loop will stop the program from progressing until the result value is true.
result = false;
while (!result)
{
cout<<"Enter the time the call starts in 24-hour rotation: "<<endl;
cin>>hour>>colin>>min;
result=validateUserInputTime(hour,colin,min);
}
You also forgot to put a false return statement on validateUserInputTime. Inputting non-digit characters might also crash the program, and cin.ignore happened to fix it.
if (cin.fail())
{
cout << "Invalid time input."<<endl;
cout<<"Please try again."<<endl<<endl<<endl;
cin.clear();
cin.ignore();
return false;
}
If you want to parse what the user entered do something like this instead
std::string time;
std::getline(std::cin, time);
now check if there is a ':' auto pos = time.find(':'); if (pos != -1) {}
then take out the hour part time.substr(0,pos)
then the minute part time.substr(pos+1)
then check if they are valid hour and minutes using e.g. stoi().
also it is better to do {} while () instead of while (answer == 'y') {...}

C++ user input restrictions

I'm currently working on a program and thinking if it is possible to implement another restrictions for the user input. The restrictions that I made as of now is that the user is only allow to input alpha and spaces, hitting enter without any input will not be also accepted.
cout<<"Input customer's lastname\t\t: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyz ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
goto p1;
}
else if(lname.empty())
{
cout<<"Please enter your lastname!\n";
cin.clear();
goto p1;
}
The another restrictions that I want is if the user input is all spaces, the program will also show a message. Second, I wonder if it's possible to detect the input if the user typed it properly like (de la Cruz) the words should be only separated by one space and if not another message will show. I cant think on how to do it, I already did some research but I couldn't found any similar to this with C++. I don't know if this is possible since I'm just starting to learn C++, or maybe I don't have enough logic at all. :(
A little help from me on checking for spaces.
bool has_only_spaces(const std::string& str)
{
return str.find_first_not_of (' ') == str.npos;
}
bool has_two_consecutive_spaces(const std::string& str)
{
for (unsigned int i = 1; i < str.length(); i++)
{
if ((str[i - 1] == str[i]) && (str[i] == ' '))
{
return true;
}
}
return false;
}
int main()
{
std::string lname;
std::cout << "Input customer's last name: ";
getline(std::cin, lname);
if (has_only_spaces(lname) || has_two_consecutive_spaces(lname))
{
std::cout << "Not a valid input" << std::endl;
std::cin.clear();
}
}
Create a function to check whether the input is valid. Use the function in a while loop.
bools isInputValid(std::string const& input)
{
// add all the checks
}
Use it as:
std::cout << "Enter input\n";
while ( getline(std::cout, line) )
{
if ( isInputValid(line) )
{
break;
}
std::cout << "Input is not vaild. Try again\n";
}

How to prevent the user from entering more than one character in the below sample code?

I am facing problem in the below code. If the user enter more than one charater then my loop gets executed number of times equal to the length of the string entered by the user. My code is written in GNU c/c++ compiler.
Thanks in advance.
int continue_option()
{
char c;
loop:
fflush(stdin);
cin.ignore();
cout<<"\n\n\t\t\t\tPress (Y/y) - Continue / Press (N/n) - Exit :";
cin>>c;
if(c=='y'||c=='Y')
{
system("clear");
}
else if(c=='n'|| c=='N')
{
exit(0);
}
else
{
printf("\n\t\t\t\tInvalid Option.Try Again.....");
goto loop;
}
fflush(stdin);
}
First thing, don't use jumps. They are old style, and they make Dijkstra spin in his grave, on top of all the other bad consequences. I don't mean "vintage", I really mean old in the bad sense.
As of your question, I'd rather put the result in a std::string and only consider the first character in there:
std::string input;
std::cin >> input;
switch (input[0]) {
case 'y':
case 'Y':
//your code
break;
case 'n':
case 'N':
exit(0);
default:
std::cout << "Invalid text" << std::endl;
}
I would also refrain from using exit(), I'd rather rely on a function's return value to finally cause a return 0; in the main(), or some equivalent technique.
You can't stop the user from typing more than one character.
What you can do is ignore the rest of the line. You have already use cin.ignore() which ignores one character. You can use cin.ignore(large number) to ignore up to the large number or the end-of-line, whichever appears first.
Unlike flushing output files, fflush(stdin) doesn't really do anything.
Try using cin.get() or getch() to read just one character at a time. Also, I guess you'd be better off replacing the whole thing with a simple loop like:
char ch = '\0';
do
{
ch = getch();
}while((tolower(ch) != 'y') || (tolower(ch) != 'n'))
if(tolower(ch) == 'y')
{
//additional handling
}
else
{
exit(0);
}
Not exactly the same behavior, but should put you on track:
#include <iostream>
#include <iomanip>
bool is_valid_answer(char c)
{
switch(c)
{
case 'y':
case 'Y':
case 'n':
case 'N':
return true;
default:
return false;
}
}
bool continue_option()
{
std::cout << "Press (Y/y) to continue, (N/n) to exit: " << std::flush;
char c = '\0';
while (std::cin.get(c) && !is_valid_answer(c));
return ((c == 'y') || (c == 'Y'));
}
int main()
{
std::cout << "Continue option: " << continue_option() << std::endl;
}