C++ program stuck in an infinite loop - c++

Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!

There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.

It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}

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.

cin not accepting user input in C++

I'm a beginner in programming, and I'm trying to make a program that calculated how much radiation you've been exposed to throughout your life. For some reason, the 'cin' in my xray function doesn't accept user input, and just exits with code 0.
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
bool nearpowerplant;
int XRay; // the amount of times you got an x-ray
double tRads = 0; // your total dose of radiation in your lifetime, measured in mSv (millisievert)
int age;
//the sleep function
void sleep() {
Sleep(1000); // 1000 miliseconds = 1 second
}
/*
>system("CLS")< for clear the console
*/
//introduction and pretty much the menu
void intro() {
cout << "Welcome to the Radiation Level Calculator" << endl;
sleep();
cout << "Conceptualized and created by Anatoly Zavyalov" << endl;
sleep();
cout << "Press the ENTER key to begin." << endl;
cin.get();
}
//introduction to general questions
void genintro() {
// intro to the medical
system("CLS");
sleep();
cout << "Let's begin with general questions." << endl;
sleep();
cout << "Press the ENTER key to continue." << endl;
cin.get();
}
//medical questions
void Age() {
//age
system("CLS");
cout << "How old are you?\n" << endl;
sleep();
cin >> age;
if (age <= 0) {
cout << "Your age can't be less or equal to 0." << endl;
Age();
}
else {
tRads += (age * 2);
sleep();
cout << tRads << endl;
}
}
//live close to powerplant?
void powerplant() {
system("CLS");
cout << "Do you live within 75 kilometers of a nuclear powerplant?" << endl;
sleep();
cout << "If yes, type YES. If no, type NO." << endl;
cin >> nearpowerplant;
if (nearpowerplant = "YES") {
tRads += (age * 0.01);
}
else {}
sleep();
cout << tRads << endl;
}
void xray() {
system("CLS");
cout << "How many times have you had an x-ray?\n" << endl;
sleep();
cin >> XRay;
if (XRay < 0) {
cout << "You can't have an x-ray a negative amount of times." << endl;
}
else {
tRads += (XRay * 3.1);
}
sleep();
cout << tRads << endl;
}
//main function, put all of the loops into here
int main() {
intro(); // the introduction
genintro(); // medical intro
Age(); // asks for age
powerplant(); // asks if lives close to powerplant
xray(); // asks for x-ray
return 0;
}
EDIT: I have edited the post to include the whole code. By the way, I am using Visual Studio Community 2017.
bool nearpowerplant;
nearpowerplant is a bool. It is true or false. That is it. It's worth noting that there is no reason for this variable to be globally accessible and consuming storage for the entire run of the program. It is used twice in the program, both times in the same function. It should be an Automatic variable scoped by the function that uses it.
cout << "If yes, type YES. If no, type NO." << endl;
cin >> nearpowerplant;
Reading "YES" or "NO" into a variable of type bool fails. cin cannot convert the string input into a boolean value and cin stops accepting input until the error is cleared. It's also a good idea to remove the garbage input that caused cin to fail or guess what? cin's just going to fail again. There are hundreds of SO questions on how to handle this, so I'm just going to drop keywords here: clear and ignore.
Takeaways: Make sure the data entry matches the type of the data being entered into and test the stream after every read to make sure the read succeeded.
eg:
if (cin >> nearpowerplant)
{
// do stuff
}
else
{
// clean up
}
This solves OP's visible error, but since it is heavily entwined with the next bug they are likely to find, we might as well cover it as well.
if (nearpowerplant = "YES") {
tRads += (age * 0.01);
}
else {}
if (nearpowerplant = "YES") { uses = (assignment) where it should use == (comparison). C++ is unforgiving here because this will compile. What it really did was takes the address of the string literal "YES", test that it's not null, and set nearpowerplant to the result. Since the address of the string literal is never going to be NULL, the result is always true, and when the if tests the result, the if will always enter.
Eg: http://ideone.com/4QL2jn
So what we need is something more like
cout << "If yes, type YES. If no, type NO." << endl;
string temp;
cin >> temp;
if (temp == "YES") {
tRads += (age * 0.01);
}
else {}
Note this will skip if the user inputs "yes", "y", "Yes" or anything other than exactly "YES". How you deal with this is up to you, but std::tolower and std::transform may help somewhat.
I think with sleep() comes undefined behavior, you should test it without, the os handles user-input and you do not have to care about the user typing in. endl flushes cout, so the text is directly shown.
Edit:
Maybe system("CLS") or sleep produces a silent error.

Looping if user input invalid

I want to create a program that when a user inputs something that I didn't define, the program prompts him again.
I did it with if statements but it only loops for 1 time and doesn't do it again. I tried loops but whenever the input is false it just breaks the condition and refuses all inputs alike. In c++.
Any help is much appreciated.
#include <iostream>
#include <string>
using namespace std;
void xD(){string x;
do{cout << "Retry\n";
cin >> x;}while(true);}
//declaring a function to make the shop
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
// if u chose bow you get this and get to choose again
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;}
/*now the problem that whenever I excute the code and type something other than bow it gives me the cin only once more and then fails even if I type bow in the 2nd attempt*/
//in my desperate 5k attempt, I tried creating a function for it.. no use.
//i want it o keep prompting me for input till i type "bow" and the other block excutes. but it never happens.
else{xD();}
}
int main(){
string name;
string i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if(i == "shop"){shop();}
else{cin >> i;}
return 0;
}
The problem lies on the condition in this loop block
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(true);
}
The while(true) condition makes it loops forever regardless of the input. To fix this, you can change the condition:
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(x!="bow");
cout << "you bought the bow. and some other messages"<<endl;
}
That should work. However, it is still too complicated for me. This can be simplified into the snippet below:
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
while (x!="bow"){
cout << "Retry\n";
cin>>x;
}
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;
}
Instead of doing this approach (which is checking the condition only once):
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << "
coins." << endl; cin >> x;
} else{
xD();
}
which is actually a RECURSIVE invocation to the method xD()
you should do a do-while loop,
example:
while (x.compare("bow") != 0)
{
cout << "sorry, wrong input, try again...";
cin >> x;
}
note the use of the compare method instead of the == operator
here more about it in the documentation
You can use return value of cin >> [your input object] here to check status or istream's method fail(). As soon as input stream fails to parse whole or part of streams it fails and stay in state of failure until you clear it. Unparsed input is preserved (so you can try to parse it differently?)m so if you try to >> again to object of same type, you'll get same failure. To ignore N chars of imput, there is method
istream::ignore(streamsize amount, int delim = EOF)
Example:
int getInt()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter an int value: ";
long long x; // if we'll use char, cin would assume it is character
// other integral types are fine
std::cin >> x;
// if (! (std::cin >> x))
if (std::cin.fail()) // has a previous extraction failed?
{
// yep, so let's handle the failure, or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
}
// Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
else if(( x > std::numeric_limits<int>::max()) ||
( x < std::numeric_limits<int>::min()))
{
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return x;
}
}
For strings parsing is almost always successful but you'll need some mechanism of comparison of string you have and one that is allowed. Try look for use of std::find() and some container that would contain allowed options, e.g. in form of pair<int,string>, and use int index in switch() statement (or use find_if and switch() within the function you give to it).
Consider that if() statement is a one_direction road, it checks the condition and if the condition was satisfied it goes to its bracket and do blah blah blah , if there is any problem with condition compiler passes ifand jump to compile other codes.
Every time that you begin to compile the codes it begins from int main() function. You did the wrong thing in the if and else statements again
Here is the correct code .I did the necessary changes.
#include "stdafx.h"
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
#define coins 500 ;
#define bow_cost 200 ;
int shop(string x)
{
//There is no need to allocate extra memory for 500 and 200 while they are constant.``
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
do
{
cout << "Input another :\n";
cin >> x;
if (x == "bow")
{
return (coins - bow_cost); //return to function as integer
}
} while (true);
}
int main()
{
string name, i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if (i == "shop")
{
cout << "Input :\n";
cin >> name;
cout << shop(name) << "you bought the bow.\n you now have " << " coins." << "\n";
}
//argument passed to shop funnction parameters.
system("pause");
return 0;
}

Assigning the "Enter Key" value to a string [C++]

In this rather simple exercise I have to receive an user input, store said input into a string, pass the string to a function by reference and finally modify the string so that every character is "parsed" by the toupper() function.
However, should the user insert 'q' as input, the program stops saying "Bye" OR if he just presses the Enter Key, the program is supposed to say something like "Hey, this string is empty".
Now the real problem here is in the last part since my code won't manage the case where the user inputs only the Enter Key value (to be honest, even if I just text a bunch of spaces followed by the Enter Key, nothing happens)
void uppercase(std::string &);
int main(){
using namespace std;
string ex2;
cout << "Exercise 2" <<endl;
while(ex2!="Bye"){
cout << "Enter a string(q to quit): ";
cin >> ex2;
cout << "Was: " << ex2 << endl << "Now is: ";
uppercase(ex2);
}
return 0;
}
void uppercase(std::string &str){
using namespace std;
if(str[0]=='\n')
cout <<"Empty string dude!" << endl;
else{
if(str.length()==1 && str[0]=='q'){ //press 'q' to exit program
str="Bye";
cout << str;
}
else{ //uppercase
for(int i=0;i<str.length();i++){
str[i]=(toupper(str[i]));
}
cout << str <<endl;
}
}
}
I also tried the compare() function and even to compare the whole string to null (pointless, but still worth a shot) and to the string "";
Sorry for the bad interpretation of your problem, trying
if( (str.length()==1 && str[0]=='q') || str.length() == 0)
{}
May help you out of the problem

Switch-statement inside a while-loop which loop infinitely

Here is my code:
int main()
{
int nothing;
string name;
int classnum;
bool classchosen;
string classname;
cout << "Welcome adventurer, your journey is about to begin.\n\n";
cout << "Firstly, what's your name? ";
cin >> name;
classchosen = false;
while (classchosen == false)
{
cout << "\n\nNow, " << name << ", choose your class entering its number.\n\n";
cout << "1- Warrior\n" << "2- Mage\n" << "3- Paladin\n" << "4- Monk\n\n";
cout << "Class number: ";
cin >> classnum;
switch(classnum){
case 1:
classname = "Warrior";
classchosen = true;
break;
case 2:
classname = "Mage";
classchosen = true;
break;
case 3:
classname = "Paladin";
classchosen = true;
break;
case 4:
classname = "Monk";
classchosen = true;
break;
default:
cout << "\nWrong choice, you have to enter a number between 1 and 4.\n" << endl;
break;
}
}
cout << "\nSo you are a " << classname << " ? Well, tell me something more about you...\n";
cin >> nothing;
return 0;
}
Now, when I run it and input a string (for example "fjdfhdk") when it asks about the class number, the program loops infinitely instead of going in the default statement, writing again the question and letting me choose another class. Why?
Try something like this:
#include <sstream>
#include <string>
using namespace std;
int getInt(const int defaultValue = -1){
std::string input;
cin >> input;
stringstream stream(input);
int result = defaultValue;
if(stream >> result) return result;
else return defaultValue;
}
//..in main
cout << "Class number: ";
int classNum = getInt();
switch(classNum){ .... }
The reason why it fails in your case is because cin is trying to read a bunch of chars into a int variable. You can either read it as a string and convert as necessary, or you can check the cin state explicitly when reading into a int variable by checking if any of the fail bits are set. The fail bits would be set if for example you try to read bunch of chars into an int.
Because you're reading into an int, and the read fails. This
has two effects:
your use of classnum afterwards is undefined behavior, and
the stream has memorized the error condition, so you can
check it later.
As long as the error condition is not cleared, all further
operations on the stream are no-ops. The simplest changes in
your program to make this work would be:
std::cin >> classnum;
if ( !std::cin ) {
classnum = 0;
std::cin.clear();
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
switch ( classnum ) // ...
In case of an error, this sets classnum to a known value,
clears the error state, and skips all input up to the next
newline. (Otherwise, you'll just fail again, because the
characters which triggered the error are still there.)
Consider, however, using a separate function to extract the int,
and using getline, as per user814628's suggestion. The above
is more to explain to you what is happening, and why your see
the symptoms you see. user814628's suggestion is far better
software engineering.