How can I stop input repeating for each char inputted? - c++

I'm trying to write a prompt where it asks the user to confirm an operation, with Y/N as the only two options.
If the user inputs Y, it does something, if the user inputs N it does something else. However if the user inputs anything other than Y or N, it simply repeats the question until either Y or N is pressed.
This is what i've got so far:
char result = '\0';
while (result != 'y' || result != 'n')
{
char key = '\0';
cout << "Do you wish to continue & overwrite the file? Y/N: ";
cin >> key;
result = tolower(key);
}
if (result == 'y')
{
cout << "YES!" << endl;
}
else if (result == 'n')
{
cout << "NO!" << endl;
}
And my problem is that if I enter multiple invalid characters, it displays the prompt again for each invalid character, like so:
Do you wish to continue & overwrite the file? Y/N: abc
a
Do you wish to continue & overwrite the file? Y/N: b
Do you wish to continue & overwrite the file? Y/N: c
Do you wish to continue & overwrite the file? Y/N:
What am I doing wrong?

So if my input was stored as a string (rather than a char), I wouldn't get the repetition for each char inputted. Also, my while loop condition should have been AND instead of OR:
string result = "";
while (result != "y" && result != "n")
{
cout << "Do you wish to continue & overwrite the file? Y/N: ";
cin >> result;
transform(result.begin(), result.end(), result.begin(), ::tolower);
}
if (result == "y")
{
cout << "YES!" << endl;
}
else if (result == "n")
{
cout << "NO!" << endl;
}

Related

Stuck on infinite loop

noob programmer here. Taking my first CS class in college and making first post on here so excuse me if the info i provide is not sufficient in advanced.
Still trying to figure out loops. Seem to get it but once there is loops within loops or if statements inside loops, I get thrown off and have no idea on how to proceed. For my assignment, I need the following to occur.
Would you like to process all the records in the file? (y/n) W
Please enter either y or n.
Would you like to process all the records in the file? (y/n) n
Enter number of records to process: two
XXXXXXXXXX Error-non numeric or negative value, try again
Enter number of records to process: 10
Here is my code:
char a = 0; //User chooses Y or N
int ProcessAmount = 0; //Amount of times to process if not all
cout << "Would you like to process all the records in the file? (y/n) ";
cin >> a;
do{
bool notDone = true;
if(a == 'n'){
while(notDone){
cout << "Enter records to process: ";
cin >> ProcessAmount;
if (cin.fail()){
cin.clear();
cin.ignore(40,'\n');
cout << "" << endl;
}
else{
notDone = false;
}
}
}else if(a != 'y' or a != 'n');
cout <<"Please enter either y or n." << endl;
}while( a != 'y');
Most problems are explained in comments, here is how I would fix it:
char a = 0; //User chooses Y or N
int ProcessAmount = 0; //Amount of times to process if not all
cout << "Would you like to process all the records in the file? (y/n) ";
cin >> a;
while (a != 'y') {
bool notDone = true;
if(a == 'n'){
while(notDone){
cout << "Enter records to process: ";
cin >> ProcessAmount;
if (cin.fail()){
cin.clear();
cin.ignore(40,'\n');
cout << "" << endl;
} else {
notDone = false;
}
}
} else if(a != 'y' or a != 'n') {
cout <<"Please enter either y or n." << endl;
cin >> a; // Need to get new input because old one is invalid.
}
};
Also I don't see how notDone is used. Also I would strongly advise of using proper indentation, spaces around keywords as while, for, if, else as it is good style.
You just put the y/n solicitation out of your loop then 'a' won't never change its value. Take a look of the change you may want:
do {
cout << "Would you like to process all the records in the file? (y/n/f) "; //f to break the loop
cin >> a;
bool notDone = true;
if (a == 'n') {
//. . .
} else if (a == 'y') {
//You may want to do something when yes
} else if (a != 'f')
cout <<"Please enter either y/n or f." << endl;
} while( a != 'f')

Validating binary input in C++

Hi i'm attempting to validate a user input looking for an input of either 1 or 0. The string validating part seems to work fine but any integer based input has the console window accepting the input but not jumping over the if statement, returning the input (maxItems). Here is the code :
int RollingStats::GetOption()
{
int maxItems;
std::cout << "Please enter either to store data individually (0) or as a range(1)" << std::endl;
std::cin >> maxItems;
if ((!(std::cin >> maxItems) && maxItems != 0) | (!(std::cin >> maxItems) && maxItems != 1))
{
std::cin.clear();
std::cin.ignore(100, '\n');
std::cout << "Please enter an input of either 0 or 1" << std::endl;
GetOption();
}
return maxItems;
}
Any help would be appreciated.
Some issues in the code:
Using cin thrice (once before if and twice in the if condition) would require the user to input thrice
Using logical OR (||) instead of bit-wise or (|) in your if condition check.
Not checking if the input is an integer
You can do something like this instead:
int RollingStats::GetOption()
{
int maxItems;
std::cout << "Please enter either to store data individually (0) or as a range(1)" << std::endl;
std::cin >> maxItems;
if(!std::cin.good() || maxItems != 0 && maxItems != 1)
{
std::cin.clear();
std::cin.ignore(100, '\n');
std::cout << "Please enter an input of either 0 or 1" << std::endl;
maxItems = GetOption();
}
return maxItems;
}

Reprompt user after invalid input-c++

I modified the original code and the first two invalid input prompts work fine. when I implement the same logic into this prompt to start a new game, my program will not recognize an invalid input, with any key entered it will start a new game.
void newGame()
{
char newGameChoice = 'a';
cout << "\n--------------------------------------------------------------------------------" << endl;
cout << "Press N to play a new game\n";
cout << "Press X to exit\n\n";
cout << "--------------------------------------------------------------------------------" << endl;
cin >> newGameChoice;
newGameChoice = toupper(newGameChoice);
if (newGameChoice == 'N');
{
char userIn = 'a';
char c = 'a';
game(userIn, c);
}
while (newGameChoice != 'N' || 'X')
{
cout << "--------------------------------------------------------------------------------";
cout << "\n Invalid input. Please try again.\n" << endl;
cout << "--------------------------------------------------------------------------------" << endl;
newGame();
}
}
Your problem is this:
if (begin != 'B');
{
...
cin >> begin;
begin = toupper(begin);
start(); <------
You're calling start() again, which will read yet another value into begin.
Please spend more time analyzing your code before posting for help, it will help you to grow as a developer much more.
while (newGameChoice != 'N' || 'X')
is equivalent to
while (newGameChoice != 'N' || 'X' != 0)
Maybe what you mean is
while (newGameChoice != 'N' || newGameChoice != 'X')
Edit:
The code is wrong, it has to be rewritten, here is a suggestion:
void newGame()
{
char newGameChoice = 'a';
while (true) {
while (true) {
cin >> newGameChoice;
newGameChoice = toupper(newGameChoice);
if (newGameChoice != 'X' && newGameChoice != 'N') {
// Wrong input print error message
} else {
break;
}
}
if (newGameChoice == 'X') {
return;
}
game('a', 'a');
}
}
Part of your problem is that your start() method isn't designed in the most logical way. Currently when an invalid input is given, you attempt to read in another input and call start() again. When you called start() for the second time it starts back at the beginning of the start() method with no knowledge of the previous input.
What you should do instead is use a while() loop when an invalid entry is given and don't continue until a proper input is entered.
void start()
{
...
//Get initial user input
while begin != 'B'
{
Keep getting input if wrong
}
game(userIn, c);
}

C++ cin gets skipped, even after I use cin.ignore()

Just to make clear, I am very new to C++.
But I wrote I very small program to test my skill with arrays and ran into a problem with cin.
If the user enters number, like the program expects them to, all is well. But if a string gets entered, all input is skipped and the program ends.
I set up all of my inputs like this: cin >> x;cin.clear();cin.ignore();
So what is awry??
Here is the full code:
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
system("cls");
int create = 1;
int entry;
int x;
string chc;
cout << "How long should the array be?" << endl;
cout << ":";
cin >> x;cin.clear();cin.ignore();
if(x<1){x=1;}
int myArray[x];
string askcontinue;
for(int x=0;x<sizeof(myArray)/sizeof(myArray[0]);x++){
system("cls");
cout << "Enter value #" << x+1 << endl;
cout << ":";
cin >> entry;cin.clear();cin.ignore();
myArray[x]=entry;
}
system("cls");
cout << "Index - Value" << endl;
for(int x=0;x<sizeof(myArray)/sizeof(myArray[0]);x++){
cout << x << " ------ " << myArray[x] <<endl;
}
system("cls");
cout << "Restart? [Y/N]" << endl;
cout << ":";
cin >> chc;cin.clear();cin.ignore();
if(chc=="y" || chc=="Y"){main();}
}
cin >> x;cin.clear();cin.ignore();
This thing that you're doing throughout your program is part of the problem. If the user enters something that doesn't meet the formatting requirements for an integer, the stream goes into a failure state. Directly after that happens you clear the stream and discard the next character. If the user entered in more than one character as part of the invalid input, the ignore() call is simply discarding the next character, but not all of the invalid input.
You need to check if the input did not succeed, and then discard the input using the overload of ignore() that takes the number of characters you wish to discard. Do the following if you wish to consistently ask the user for input if he does not provide valid characters:
while (!(std::cin >> x)) {
std::cout << "How long should the array be?" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
But judging from your code, it doesn't look like you want to repeatedly ask the user for input. In that case, you should check for valid input instead and do nothing in the invalid case:
if (std::cin >> x) {
...
}
Also, VLAs (or variable-length arrays) are a non-standard feature of C++, provided as extentions in some compilers. Don't use them. Instead, allocate dynamically by using std::vector:
std::vector<int> myArray(x);
NOTE: you should also change the fact that you defining the variable 'x' three times
the problem you are having, is that c input does not type checking, so it does not care what was entered, so this is up to you. You should input everything as a string, and then make sure that the string contains nothing but numbers, THEN you can use std::stoi, or whatever the appropriate conversion method is. if they DO NOT enter a valid number, then you can just say INVALID, and tell the user to enter a valid number, and go back to the input, you could use something such as:
system("cls");
cout << "Enter value #" << x + 1 << endl;
cout << ":";
cin >> entry; cin.clear(); cin.ignore();
while(!is_valid_integer(entry))
{
system("cls");
cout << "INVALID NUMBER \n Enter value #" << x + 1 << endl;
cout << ":";
cin >> entry; cin.clear(); cin.ignore();
}
myArray[x] = std::stoi(entry);
And then entry is a string.
is_valid_integerwould be defined as:
bool is_valid_integer(std::string str)
{
for(auto it : str)
{
if(!(ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' || ch == '9'))
return false;
//OR: this is more efficient, but is reliant on using ascii codes (which in this case we are)
//if(!(ch >=48 && ch <= 57)) return false;
}
return true;//all numbers
}

Double Line when user is asked to press i to view Inventory

Hey Basically i have 2 functions:
void Inventory:: showInventory()
{
char input[80];
cin >> input;
char inventoryRequest[] = "i";
//compare the player input to inventoryRequest (i) to see if they want to
//look at inventory.
int invent = strcmp (input,inventoryRequest);
if(invent == 0) {
//vector<string> inventory;
cout << "You have " << inventory.size() << " items.\n";
cout << "\n******Inventory******";
cout << "\nYour items:\n";
for (int i= 0; i< inventory.size(); ++i) {
cout<< inventory[i] << endl;
}
}
}
void Inventory :: displayInventory(const string str) {
char input = 0;
do
{
cout << str << endl;
cin >> input;
}
while((input != 'i') && (input != 'I') && (input != 'n') && (input != 'N'));
showInventory();
//return input;
}
showInventory compares the player input to i.
display inventory only lets the user press i or n.
i to view the inventory and n to skip.
But when i is pressed. It causes a double line.
Meaning i has to be pressed twice to view the inventory.
I have tried numerous things to stop this from occuring. But i have not succeeded and most of the time the inventory cannot be viewed at all.
Can anybody help me with this.
Thanks in advance.
Try using a parameter for input on void Inventory::showInventory(), and eliminating the second cin, something like this:
void Inventory:: showInventory(char input)
{
//char input[80];
//cin >> input;
//char inventoryRequest[] = "i";
//int invent = strcmp (input,inventoryRequest);
//compare the player input to inventoryRequest (i) to see if they want to look at inventory.
//if(invent == 0) // REPLACE THIS WITH THE LINE BELOW
if(input == 'i')
And then when you call it, do it like this:
showInventory(input);