In my code, the while loop prints the cout twice when it should print it once, as well as the function's couts. I don't understand why it's doing this - it is supposed to display
What would you like to do?
Deposit
Withdraw
Cancel
But, it displays that twice.
while (yesNo == 'Y') {
cout << "What would you like to do?"
<< endl
<< endl;
menu();
getline(cin, bankChoice);
if (bankChoice == "Withdraw")
{
withdrawTotal = withdraw(bankAmount);
bankAmount = withdrawTotal;
cout << "You now have $"
<< bankAmount
<< " in your account."
<< endl;
cout << "Would you like to do anything else?"
<< endl
<< "Y/N: ";
cin >> yesNo;
}
if (bankChoice == "Deposit")
{
depositTotal = deposit(bankAmount);
bankAmount = depositTotal;
cout << "You now have $"
<< bankAmount
<< " in your account."
<< endl;
cout << "Would you like to do anything else?"
<< endl
<< "Y/N: ";
cin >> yesNo;
}
if (bankChoice == "Cancel") {
return 0;
}
}
That is the loop I am using. If additional code is needed I can post it as well, but this is the part that is causing the issue. I've tried the code without it and it works fine, but I'd like to get the code to loop until the user enters 'N'.
You are using both std::getline and operator>> to read from std::cin. operator>> does not consume the trailing newline, so the next call to std::getline() will immediately read the following newline and interpret it as an empty line of text that was entered. This will run through the loop, and go back up to the top, for the second prompt.
Never use operator>> with std::cin when you intend to read a single line of text.
The following short example demonstrates this point:
#include <iostream>
#include <string>
int main()
{
char c;
std::string l;
std::cin >> c;
std::cout << "A line of text please: ";
std::getline(std::cin, l);
}
Run it, enter "Y", and try to figure it out, yourself, why the program terminates immediately.
Once again: don't use operator>> to read lines of text from std::cin. It is a recipe for grief, and bugs.
In addition to Sam's answer, I'd like to recommend that you extract common functionality outside your two if statements:
std::string yesNo;
while (yesNo.compare("Y") == 0) {
cout << "What would you like to do?"
<< endl
<< endl;
menu();
getline(cin, bankChoice);
if (bankChoice == "Cancel")
return 0;
if (bankChoice == "Withdraw") {
withdrawTotal = withdraw(bankAmount);
bankAmount = withdrawTotal;
}
if (bankChoice == "Deposit") {
depositTotal = deposit(bankAmount);
bankAmount = depositTotal;
}
cout << "You now have $"
<< bankAmount
<< " in your account."
<< endl;
cout << "Would you like to do anything else?"
<< endl
<< "Y/N: ";
std::getline(std::cin, yesNo);
}
Related
I am prompting the user to enter an integer value. When the value is incorrect, the program works. However, when the user enters an integer input, the user needs to enter the input twice.
I looked at other tutorials on how to use the while loop to catch erroneous input, and that part worked for me. However, the integer values need to be entered twice in order for the program to run.
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
cin >> input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
You ask for the input twice:
cin >> input;
while(!(cin >> input )){
Removing the first line might make it work you intended.
'The user has to enter the input twice' Look at your code
int input;
cin >> input;
while(!(cin >> input )){
How many times do you ask the user for input?
You'd have more luck with this
int input;
while(!(cin >> input )){
Your error recovery code looks reasonable, haven't tested it though.
int input;
while (cout << "Your choice: ",
!(cin >> input) || input < 1 || 9 < input)
{
cin.clear();
while (cin.get() != '\n');
cerr << "Invalid input! Please try again!\n";
}
Thanks everyone! The "cin >> input;" line was unnecessary. At first, I left it there because it would actually tell the user the error message if the user entered a numeric input such as a double. So, if the user entered something like 3.3, the program would display an error message that I specified ("Please enter an integer" line). However, the program in this case (when there is a double) asks the user to prompt for the integer input twice and then continues the program. When I delete the said unnecessary line, the program accepts a double input, but what it does, it takes the numeric value before the decimal point and uses it as the integer. So, a value of 1.2 is recorded as 1 when I tested it. I'm unsure why this phenomenon happens, but the program works otherwise. Maybe it accounts for human error?
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
I am currently taking a C++ programming class and am working on a project in which I have to create a fairly simple movie database. My code essentially works as intended yet in certain cases it causes the main menu to loop infinitely and I cannot figure out why. I brought this to my teacher and he cannot explain it either. He gave me a workaround but I would like to know if anyone can see the cause of the problem. Full code is as follows:
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct MovieType
{
string title;
string director;
int year;
int length;
string rating;
};
MovieType addMovie() {
MovieType newMovie;
cout << "Movie title :";
getline(cin, newMovie.title);
cout << "Director :";
getline(cin, newMovie.director);
cout << "Year :";
cin >> newMovie.year;
cout << "Length(in minutes) :";
cin >> newMovie.length;
cout << "Rating :";
cin >> newMovie.rating;
cout << endl;
return newMovie;
}
void listMovie(MovieType movie) {
cout << "______________________________________" << endl;
cout << "Title : " << movie.title << endl;
cout << "Director : " << movie.director << endl;
cout << "Released : " << movie.year << endl;
cout << "MPAA Rating : " << movie.rating << endl;
cout << "Running time : " << movie.length << " minutes" << endl;
cout << "______________________________________" << endl;
}
void search(vector<MovieType> movieVector) {
string strSearch;
cout << endl << "Search title: ";
getline(cin, strSearch);
for (int c = 0; c < movieVector.size(); c++) {
if (movieVector.at(c).title == strSearch)
listMovie(movieVector.at(c));
}
}
int main() {
bool quit = 0;
vector<MovieType> movieVector;
while (quit == 0) {
char selection = 'f';
cout << "Main Menu:" << endl;
cout << "'a' - Add movie" << endl;
cout << "'l' - List movies" << endl;
cout << "'s' - Search by movie title" << endl;
cout << "'q' - Quit" << endl;
cout << "Please enter one of the listed commands:";
cin >> selection;
cin.ignore();
cout << endl;
if (selection == 'a')
movieVector.push_back(addMovie());
else if (selection == 'l') {
for (int c = 0; c < movieVector.size(); c++) {
listMovie(movieVector.at(c));
}
}
else if (selection == 's') {
search(movieVector);
}
else if (selection == 'q')
quit = 1;
}
return 0;
}
When an unexpected input type is entered during the addMovie function(like entering text for the int type year), it just runs through the function then loops through the menu infinitely. It appears to me that the code just stops even looking at the input stream. I have tried using cin.ignore() in many different places but it doesn't matter if there is nothing left in the stream it just keeps going.
I am using NetBeans to compile my code.
I really have no idea why it behaves like this otherwise I would offer more information but I am just curious as to why this happens, because as I said before, my professor doesn't even know why this is happening.
Any help or insight is greatly appreciated.
cin enters an error state where cin.fail() is true. In this state it just ignores all input operations. One fix is to clear the error state, but better, only use getline operations on cin, not formatted input.
E.g., instead of
cin >> newMovie.year;
… do
newMovie.year = stoi( line_from( cin ) );
… where line_from can be defined as
auto line_from( std::istream& stream )
-> std::string
{
std::string result;
if( not getline( stream, result ) )
{
// Throw an exception or call exit(EXIT_FAILURE).0
}
return result;
}
Disclaimer: code untouched by compiler.
I am a very newbie programmer, so I don't really know much about writing code to protect the application.. Basically, I created a basicMath.h file and created a do while loop to make a very basic console calculator (only two floats are passed through the functions). I use a series of if and else if statements to determine what the users wants to do. (1.add, 2.subtract, 3.multiply, 4.divide) I used a else { cout << "invalid input" << endl;} to protect against any other values, but then I tried to actually write a letter, and the program entered a infinite loop. Is there anyway to protect against users who accidentally hit a character instead of a number?
`#include <iostream>
#include "basicMath.h"
using namespace std;
char tryAgain = 'y';
float numOne = 0, numTwo = 0;
int options = 0;
int main()
{
cout << "welcome to my calculator program." << endl;
cout << "This will be a basic calculator." << endl;
do{
cout << "What would you like to do?" << endl;
cout << "1. Addition." << endl;
cout << "2. Subtraction." << endl;
cout << "3. Multiplication" << endl;
cout << "4. Division." << endl;
cin >> options;
if (options == 1){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " + " << numTwo << " = " << add(numOne, numTwo) << endl;
}
else if (options == 2){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " - " << numTwo << " = " << subtract(numOne, numTwo) << endl;
}
else if (options == 3){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " * " << numTwo << " = " << multiply(numOne, numTwo) << endl;
}
else if (options == 4){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " / " << numTwo << " = " << divide(numOne, numTwo) << endl;
}
else {
cout << "Error, invalid option input." << endl;
}
cout << "Would you like to use this calculator again? (y/n)" << endl;
cin >> tryAgain;
}while (tryAgain == 'y');
cout << "Thank you for using my basic calculator!" << endl;
return 0;
}
`
One way would be to use exception handling, but as a newbie you're probably far from learning that.
Instead use the cin.fail() which returns 1 after a bad or unexpected input. Note that you need to clear the "bad" status using cin.clear().
A simple way would be to implement a function:
int GetNumber ()
{
int n;
cin >> n;
while (cin.fail())
{
cin.clear();
cin.ignore();
cout << "Not a valid number. Please reenter: ";
cin >> n;
}
return n;
}
Now in your main function wherever you are taking input, just call GetNumber and store the returned value in your variable. For example, instead of cin >> numOne;, do numOne = GetNumber();
When you input to cin, it is expecting a specific type, such as an integer. If it receives something that it does not expect, such as a letter, it sets a bad flag.
You can usually catch that by looking for fail, and if you find it, flush your input as well as the bad bit (using clear), and try again.
Read a whole line of text first, then convert the line of text to a number and handle any errors in the string-to-number conversion.
Reading a whole line of text from std::cin is done with the std::getline function (not to be confused with the stream's member function):
std::string line;
std::getline(std::cin, line);
if (!std::cin) {
// some catastrophic failure
}
String-to-number conversion is done with std::istringstream (pre-C++11) or with std::stoi (C++11). Here is the pre-C++11 version:
std::istringstream is(line);
int number = 0;
is >> number;
if (!is) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
} else if (!is.eof()) {
// line is a number, but ends with a non-number, e.g. "123abc",
// whether that's an error depends on your requirements
} else {
// number is OK
}
And here the C++11 version:
try {
std::cout << std::stoi(line) << "\n";
} catch (std::exception const &exc) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
std::cout << exc.what() << "\n";
}
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.
I have a personal project I've been working on. To work, it needs to accept a lot of data (relatively) from the user, in the form of four different kinds of data for 12 users. As such, I have quite a lengthy sequence of statements similar to this:
cout << '\n' << "Monster A's name is: ";
cin >> nameA;
cout << '\n' << "Monster A rolled: ";
cin >> rollM_A;
cout << '\n' << "Monster A's Dex is: ";
cin >> DexA;
cout << '\n' << "Monster A's Mod is: ";
cin >> ModA;
cout << '\n' << "Monster A's Level is: ";
cin >> LvlA;
etc.
Occasionally, however, there might only be a need to input data for less than 12 monsters, say, 5-6 or even 1-2. I'd like to be able to use a command to skip the input section to the rest of the code based on something like a keystroke. i.e. If the user has put in data for 5 monsters, and that's all they require, they could hit the backslash to skip the rest of the input sequence.
Does what I'm talking about make any sense/is there an STL command to do what I'm looking for? Currently, this process isn't looped, but would exiting it be easier if it was inside a loop? I did have a thought of trying something like this:
while(cin.get() != '\') {
cout << '\n' << "Monster A's name is: ";
cin >> nameA;
//etc...
}
EDIT: The above attempt builds, but upon entering the desired keystroke, it quickly and endlessly prints the user prompts without accepting data. Any advice? All I want is for it to break and move on. Can I use a switch statement effectively?
Thanks!
That could work. You can also use EOF, which is more general, than '\'. Then when you are done, hit Ctrl-D to send the EOF, and you are done. This takes care of the situation when some player enters '\' as the Monster's name.
I just tested this set of code and it seems to work how you would like. Of course you will have to modify it to fit your original application.
std::string in;
while (true) {
std::cout << "Enter a name\n";
std::cin >> in;
if (in == "#")
break;
std::cout << "\nMonster A's name is: " << in << "\n";
}
In order to incorporate the limit of the number of monsters, rather than having the true parameter passed into the while loop, simply add a counter to how many monsters are created and break on that condition:
int num_monsters = 0;
while (num_monsters <= 12) {
...
num_monsters++;
}
Hope this helps.
You can check if the name is \, it is not user friendly but it works.
string name;
while (name != "\\") {
cout << '\n' << "Monster A's name is: ";
cin >> name;
cout << "Received " << name << '\n';
if (name != "\\") {
// do something with name ...
}
}
If the loop still loops endlessly, refer to How do I flush the cin buffer? and try clearing stdin buffer.
[edit] I fixed an error in the loop
Here's something I wrote.
struct Monster {
string name;
bool roll;
float dex;
float mod;
float level;
Monster(void) :
name(),
roll(false),
dex(0),
mod(0),
level(0) { }
};
bool getMonsterInformationFromStdin(int index, Monster& monster) {
string end_char = "\\";
string name, roll, dex, mod, level;
cout << '\n' << "Monster " << index << "'s name is: ";
cin >> name;
if (name.compare(end_char) == 0) return false;
monster.name = name;
cout << '\n' << "Monster " << index << " rolled: ";
cin >> roll;
if (roll.compare(end_char) == 0) return false;
monster.roll = (roll[0] == 'y' || roll[0] == 'Y') ? true : false;
cout << '\n' << "Monster " << index << "'s Dex is: ";
cin >> dex;
if (dex.compare(end_char) == 0) return false;
monster.dex = atof(dex.c_str());
cout << '\n' << "Monster " << index << "'s Mod is: ";
cin >> mod;
if (mod.compare(end_char) == 0) return false;
monster.mod = atof(mod.c_str());
cout << '\n' << "Monster " << index << "'s Level is: ";
cin >> level;
if (level.compare(end_char) == 0) return false;
monster.level = atof(level.c_str());
return true;
}
int main(int argc, char** argv) {
int max_monsters = 10;
for (int i = 0; i < max_monsters; i++) {
Monster m;
if( !getMonsterInformationFromStdin(i, m) ) break;
string roll = m.roll ? "rolled" : "didn't roll";
cout << m.name << " " << roll << " dex: " << m.dex << " mod: " << m.mod << " level: " << m.level << endl;
}
return 0;
}
I think this is problem can be solved by using a sentinel Monster name, as u can see below.
const string SentinelName = "%^&";
while(true)
{
cout << '\n' << "Monster A's name is(if u want to end, pls input %^&): ";
cin >> nameA;
if(strcmp(nameA, SentinelName.s_str())
break;
cout << '\n' << "Monster A rolled: ";
cin >> rollM_A;
cout << '\n' << "Monster A's Dex is: ";
cin >> DexA;
cout << '\n' << "Monster A's Mod is: ";
cin >> ModA;
cout << '\n' << "Monster A's Level is: ";
cin >> LvlA;
}
Hope this can solve ur problem. Besides, A little advice for ur code, u can encapsulate the attributes of the monster, such as the name, mode level, etc into a class and this will make ur code look fancier.