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

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') {...}

Related

Whats a good way to get the program to end based on user input?

I did my "Hello World", I'm just getting started on my programming adventure with C++. Here is the first thing I've written, what are some ways to get it to end with user input? I'd like a yes or no option that would terminate the program. Also any feedback is welcome, thank you
#include <iostream>
using namespace std;
void Welcome();
void calculateNum();
void tryAgain();
int main() {
Welcome();
while (true) {
calculateNum();
tryAgain();
}
system("pause");
}
void calculateNum() {
float userNumber;
cin >> userNumber;
for (int i = 100; i >= 1; i--) {
float cNumber = i* userNumber;
cout << i << " >>>>> " << cNumber << endl;
}
}
void Welcome() {
cout << "Welcome \n Enter a number to see the first 100 multiples \n";
}
void tryAgain() {
cout << "Try again? Enter another number... ";
}
Here is one option:
Switch to do ... while loop, with the condition at the end.
Make your tryAgain() function return a boolean and put it in the while condition.
In tryAgain function read input from the user, and compare it to expected answers.
First, lets add a new header for string, it will make some things easier:
#include <string>
Second, lets rebuild the loop:
do {
calculateNum();
} while (tryAgain());
And finally, lets modify the function:
bool tryAgain() {
string answer;
cout << "Try again? (yes / no)\n";
cin >> answer;
if (answer == "yes") return true;
return false;
}
Now, there is a slightly shorter way to write that return, but it might be confusing for new learners:
return answer == "yes";
You don't need the if because == is an operator that returns bool type value.
You can change your calculateNum() in the following way:
Change the return value of your calculateNum() function into bool to indicate whether the program shall continue or stop
read the input into a std::string
check if the string is equal to your exit string like 'q' for quit
3.a in that case, your function returns false to indicate the caller that the program shall stop
3.b otherwise, create a stringstream with your string and read the content of the stream into your float variable and continue as you do like now
In your loop in your main function you break if calculateNum() returned false
Here is a simple solution:
#include <iostream>
// Here are two new Includes!
#include <sstream>
#include <string>
using namespace std;
void Welcome();
// Change return value of calculateNum()
bool calculateNum();
void tryAgain();
int main()
{
Welcome();
while (true)
{
if (!calculateNum())
break;
tryAgain();
}
system("pause");
}
bool calculateNum()
{
//Read input into string
string userInput;
cin >> userInput;
//Check for quit - string - here just simple q
if (userInput == "q")
return false;
//otherwise use a std::stringstream to read the string into a float as done before from cin.
float userNumber;
stringstream ss(userInput);
ss >> userNumber;
//and proces your numbers as before
for (int i = 100; i >= 1; i--)
{
float cNumber = i * userNumber;
cout << i << " >>>>> " << cNumber << endl;
}
return true;
}
void Welcome()
{
cout << "Welcome \n Enter a number to see the first 100 multiples \n";
}
void tryAgain()
{
cout << "Try again? Enter another number... ";
}
Having your users input in a string you can even do further checks like checking if the user entered a valid number, interpret localized numbers like . and , for decimal delimitters depending on your system settings and so on.

Queue using struct (Taxi dispatch problem)

I want to write program that reads command from user, when d is entered a taxi is entered ,it prompts to enter driver_id and stores taxi in in queue (queue can have maximum n taxi), when command c is entered by customer it assigns the earliest taxi in the queue to the customer.
I'm trying to solve it using struct member function so that our code looks good, but although I have initialized n=4, it is only able to store 2 taxi, and shows me that the queue is full for the 3rd entry, which should not happen. Please review my approach.
Program run as such:
PS C:\Users; if ($?) { g++struct_taxi};; if ($?) { .\struct_taxi}
enter command:d
enter driverid:122
enter command:d
enter driverid:124
enter command:d
enter driverid:126
Q is full
Code:
#include<iostream>
using namespace std;
const int n=4;
struct Queue{
int elements[n],nwaiting,front;
void initialize(){
nwaiting=0;
front=0;
}
bool insert(int v){
if(nwaiting>=n)
return false;
elements[(front+nwaiting)%n]=v;
nwaiting++;
return true;
}
bool remove(int &v){
if(nwaiting==0)
return false;
else{
v=elements[front];
front=(front+1)%n;
nwaiting--;
return true;
}
}
};
int main(){
Queue q;
q.initialize();
while(true){
cout<<"enter command:";
char c;cin>>c;
if(c=='d'){
cout<<"enter driverid:";
int driverid;cin>>driverid;
if(!q.insert(driverid)){
cout<<"Q is full\n";}
else{
q.insert(driverid);
}
}
else if(c=='c'){
int driverid;
if(!q.remove(driverid)){
cout<<"No taxi available.\n";
}
else
//q.remove(driverid);
cout<<"assigning:"<<" "<<driverid<<endl;
}
}
}
The problem is that when you check the condition if(!q.insert(driverid)), you've already insert that driver into the system. Then the else statement insert it another time with q.insert(driverid);
So the solution is to simply remove the else statement.
#include<iostream>
using namespace std;
const int n=4;
struct Queue
{
int elements[n],nwaiting,front;
void initialize()
{
nwaiting=0;
front=0;
}
bool insert(int v)
{
if(nwaiting>=n) {return false;}
elements[(front+nwaiting)%n]=v;
nwaiting++;
return true;
}
bool remove(int &v)
{
if(nwaiting==0)
return false;
else
{
v=elements[front];
front=(front+1)%n;
nwaiting--;
return true;
}
}
};
int main()
{
Queue q;
q.initialize();
while(true)
{
cout<<"enter command:";
char c;
cin>>c;
if(c=='d')
{
cout<<"enter driverid:";
int driverid;
cin>>driverid;
if(!q.insert(driverid))
{
cout<<"Q is full\n";
}
}
else if(c=='c')
{
int driverid;
if(!q.remove(driverid))
{
cout<<"No taxi available.\n";
}
else {cout<<"assigning:"<<" "<<driverid<<endl;}
}
}
}
Result:
enter command:d
enter driverid:121
enter command:d
enter driverid:122
enter command:d
enter driverid:123
enter command:d
enter driverid:124
enter command:d
enter driverid:125
Q is full
An easier way obviously is to use std::queue, a data structure used for situation exactly like this, and as it came with the same functionality of your Queue struct, the code would be much shorter:
#include <iostream>
#include <queue>
using namespace std;
const int maxn=2;
int main()
{ queue<int> q;
while(true)
{
cout << "Enter command : "; char c; cin >> c;
if (c == 'd') //if inserting new driver
{
cout << "Enter driver's ID : "; int id; cin >> id; //input id
if (q.size() == maxn) {cout << "Queue is full\n";} //if size of queue is equal to maxn, no insert
else {q.push(id);} //else insert
}
else if (c == 'c')
{
if (q.empty()) {cout << "No driver available\n";} //if no driver, no assigning
else
{
int curDriver = q.front(); //take drive in front of queue
q.pop(); //take the driver id out of queue
cout << "Assigned driver : " << curDriver << "\n";
}
}
}
}
Result:
Enter command : d
Enter driver's ID : 123
Enter command : d
Enter driver's ID : 124
Enter command : d
Enter driver's ID : 125
Queue is full
Enter command : c
Assigned driver : 123
Enter command : c
Assigned driver : 124
Enter command : c
No driver available
Enter command :
Also, it's not recommended to use keywords like front, remove, etc... for variable names. And check out Why is "using namespace std;" considered bad practice?

Detect real numbers beyond whole numbers

This code is meant to detect REAL numbers from a string entered continuously by a user, and return the found real number as a double value . I was able to construct it to the point where it detects whole numbers, but if I try a decimal number it doesn't detect it. I think my error is within my isvalidReal() function, but I'm not sure how to move things around to get it to work.
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
double getaReal(); //function prototype
int value;
cout << "Enter a number: ";
value = getaReal();
cout << "the number entered is a real number: " <<value << endl;
return 0;
}
bool isvalidReal(string str) //function to find real numbers.
{
int start = 0;
int i;
bool valid = true;
bool sign = false;
if (int(str.length()) == 0) valid = false; //check for empty string
if (str.at(0) == '-' || str.at(0) == '+') //check for sign
{
sign = true;
start = 1; //check for real num at position 1
}
if (sign && int(str.length()) == 1) valid = false; //make sure there's atleast 1 char after the sign
i = start;
while (valid && i<int(str.length()))
{
if (!isdigit(str.at(i))) valid = false; //found a non-digit character
i++; // move to next character
}
return valid;
}
double getaReal()
{
bool isvalidReal(string); //function declaration prototype
bool isnotreal = true;
string input;
while (isnotreal)
{
try
{
cin >> input; //accepts user input
if (!isvalidReal(input)) throw input;
}
catch (string e)
{
cout << "No real number has been detected, continue to\n enter string values: ";
continue; //continues user input
}
isnotreal = false;
}
return atof(input.c_str());
}

I need to limit my program not to accept any decimal values in my program

I am instructed that I have to reject any decimal and I need to re enter the number again.I tried this code but still it just goes to the whole process before acknowledging the error. Try the program and judge me :D here's my code:
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<limits>
using namespace std;
int getInt()
{
int m=0;
while (!(cin >> m))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Please input a proper 'whole' number: " ;
}
return (m);
}
int main()
{
double x;
int q,w,e,choice;
cout<<"Welcome! This program will sort out the integers you will input!\nPlease input number of integers: ";
cin>>q;
cout<<endl<<endl;
int* inc= new int[q];
int* dec= new int[q];
for(int p=1;p<=q;++p)
{
w=p;
e=p;
cout<<"Input integer number "<<p<<": ";
x =getInt();
while(e>0 && inc[e-1]>x)
{
inc[e]=inc[e-1];
e--;
}
while(w>0 && dec[w-1]<x)
{
dec[w]=dec[w-1];
w--;
}
inc[e]=x;
dec[w]=x;
}
cout<<endl;
cout<<"What order do you prefer? Input 1 for increasing and 2 if decreasing.\nChoice: ";
cin>>choice;
while(choice<1 || choice>2)
{
cout<<"Please input a correct choice! Try again!\nChoice: ";
cin>>choice;
}
if(choice==1)
{
for(int i=0;i<q;++i)
cout<<inc[i]<<"\t";
cout<<endl;
}
else
{
for(int i=1;i<=q;++i)
cout<<dec[i]<<"\t";
cout<<endl;
}
system("PAUSE");
}
hoping for your help :)
You can try using modulo.
Just an idea, hope it helps.
bool flag = false;
While (flag == false){
cin>>number;
if ((number % 1) != 0){
flag = false;
}
else{
flag = true;
}
cin.clear();
}
Try making a copy of the number you want to test and casting it to an int and then back to a double, and then check for equality. If they are equal, you have an int, if they are not, you have a decimal:
#include <iostream>
using namespace std;
int main()
{
double a = 5;
double c = 5.5;
double b = a;
bool test1 = (double)((int)b) == a; //true!
b = c;
bool test2 = (double)((int)b) == c; //false!
cout << test1 << endl;
cout << test2 << endl;
return 0;
}
Wrote this answer a long time ago, it is very hacky and will not work on all inputs. Use std::stoi and check if it throws as the comment suggests instead.

How do I change the int variable in a cycle and if so is there a more efficient way?

First post ever on this site so spare my life , please.
I'm trying to do a little encryption and decryption program imitating the Enigma cipher/machine from the WW2 (enough history lessons)
So I'm trying to input a number and a letter like so : 1h 2e 3l 4l 5o ;
Because I don't use a cycle I need to write for every variable that I'm adding the number , but what do I do if I have less letters than variables?The only way I can think of is using a cycle which checks if the input is a letter or not.That's why the current code I've written only can be used for specific amount of numbers and letters...
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int opt;
cout<<"Enter 1 for encryption and 2 for decryption. "<<endl;
cin>>opt;
if(opt == 1)
{
int setting1,setting2,setting3,setting4;
char a,b,c,d;
cout<<"_________________________________________________"<<endl;
cin>>setting1>>a>>setting2>>b>>setting3>>c>>setting4>>d;
a+=setting1;
b+=setting2;
c+=setting3;
d+=setting4;
cout<<(char)a<<" "<<(char)b<<" "<<(char)c<<" "<<(char)d<<endl;
}
if(opt == 2)
{
int setting1,setting2,setting3,setting4;
char a,b,c,d;
cout<<"_________________________________________________"<<endl;
cin>>setting1>>a>>setting2>>b>>setting3>>c>>setting4>>d;
a-=setting1;
b-=setting2;
c-=setting3;
d-=setting4;
cout<<(char)a<<(char)b<<(char)c<<(char)d<<endl;
}
if(opt !=1 && opt !=2)cout<<"ERROR!"<<endl;
std::cout << "Press ENTER to continue..."<<endl;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(),'\n');
return 0;
}
Also I was told that the last 2 lines would prevent the .exec from closing after it's done doing it's thing.
I recommend inputting your data in loops (cycles). But before that is accomplished, I suggest using a structure (or class) with an overloaded stream extraction operator.
struct Number_Letter
{
int number;
char letter;
friend std::istream& operator>>(std::istream& inp, Number_Letter& nl);
};
std::istream& operator>>(std::istream& inp, Number_Letter& nl)
{
inp >> nl.number;
if (inp)
{
inp >> nl.letter;
if (!isalpha(nl.letter))
{
// Error recovery for not reading a letter
}
}
else
{
// Error recovery for failing to read number.
}
return inp;
}
Your input loop would be something like:
Number_Letter nl;
while (std::cin >> nl)
{
// process the data
}
For cryptography, you may want to keep the data as a string:
std::string message;
getline(cin, message);
for (unsigned int i = 0; i < message.length(); i += 2)
{
if (!isdigit(message[i]))
{
cerr << "Invalid message type at position " << i << endl;
break;
}
if (i + 1 > message.length())
{
cerr << "Missing letter at end of message.\n";
break;
}
if (!isalpha(message[i+1]))
{
cerr << "Invalid message type at position " << i << endl;
break;
}
}
It sounds like you're trying to check for an unknown sequence of character/integers and need a loop to do the check?
int opt;
cout<<"Enter 1 for encryption and 2 for decryption. "<<endl;
cin>>opt;
if(opt != 1 && opt != 2)
{
cout << "Error" << endl;
return -1;
}
int integer;
char character;
char again;
do
{
cout<<"_________________________________________________"<<endl;
cin>>integer>>character;
if(opt == 1) {
character+=integer;
} else if(opt == 2) {
character-=integer;
}
cout << character <<endl;
cout << "Again (Y)?: ";
cin>>again;
}while(again == 'Y' || again == 'y');
std::cout << "Press ENTER to continue..."<<endl;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(),'\n');
return 0;