"cin.ignore" hit enter twice to continue - c++

I have the following code in a for loop. When it goes through for the first time, it runs great. However, when it gets run again, it stops just before the cin.ignore, and I have to hit the enter key before I can type my input. Any reason why that is? Thanks.
cin.ignore(100, '\n');
string input;
getline(cin, input);
EDIT:
Here is the entire part of the code:
Note that the vector restaurants has 16 strings in it. And the function ifOddNumberOfRestaurants is the following:
void ifOddNumberOfRestaurants(vector<string> restaurants){
cout << "To begin the tournament, please add one more restaurant to the list: ";
cin.ignore(1000, '\n');
string newRestaurant;
getline(cin, newRestaurant);
restaurants.push_back(newRestaurant);
}
The code with problems:
else if ( option == 5 ) {
int numberRestaurants = restaurants.size();
int evenOrOdd = numberRestaurants % 2;
if (evenOrOdd == 1){
ifOddNumberOfRestaurants(restaurants);
}
vector<string> battleRestaurants(restaurants);
int stop = 0;
while ( stop == 0 ){
double half = battleRestaurants.size()/2;
int option1 = 0;
int option2 = 1;
int match = 1;
for(int i = 0; i < half; i++){
cout << "Match " << match << "/" << half << " --- " << battleRestaurants[option1] << " *OR* " << battleRestaurants[option2] << "? ";
match++;
cout << "\nBEFORE IGNORE\n";
cin.ignore(100, '\n');
cout << "\nAFTER IGNORE\n";
string winner;
getline(cin, winner);
if ( winner == battleRestaurants[option1]){
battleRestaurants.erase(battleRestaurants.begin() + option2);
}
else if ( winner == battleRestaurants[option2]){
battleRestaurants.erase(battleRestaurants.begin() + option1);
}
option1++;
option2++;
cout << "Postion of i: " << i << "\nPosition of Option 1: " << option1 << "\nPosition of Option 2: " << option2 << "\n" << endl;
printRestaurants(battleRestaurants);
}
}
}

I Think your problem is that you have the cin.ignore(100, '\n'); When you do not need it remove that and your code should work ok. I tried just a little snippet of that part and it worked fine. EX: `vector restaurants;
int numberRestaurants = restaurants.size();
int evenOrOdd = numberRestaurants % 2;
for (int i = 0; i < 5; i++)
{
if (evenOrOdd == 1){
cout << "To begin the tournament, please add one more restaurant to the list: ";
//cin.ignore(100, '\n');
string newRestaurant;
getline(cin, newRestaurant);
restaurants.push_back(newRestaurant);
}
}
Remove the ignore thats why you have to push enter before it accepts anything else because it will ignore the first 100 chars or a new line whichever comes first.

Related

set.erase() is not working for me, am I doing something wrong?

Here's my current code:
#include <iostream>
#include <set>
using namespace std;
int main()
{
string numOne, numTwo, numThree;
int pointOne, pointTwo, pointThree, totalPoint;
set<string> ansOne = { "TOE", "TONGUE", "TOOTH" };
cout << "Give A Body Part That Starts With The Letter T";
cout << "\n1. ";
cin >> numOne;
if (ansOne.find(numOne) == ansOne.end())
{
ansOne.erase(numOne);
cout << "Wrong!";
pointOne = 0 + 0;
}
else
{
cout << "Nice, You got a Point!";
pointOne = 1 + 0;
}
cout << "\n2. ";
cin >> numTwo;
if (ansOne.find(numTwo) == ansOne.end())
{
ansOne.erase(numTwo);
cout << "Wrong!";
pointTwo = 0 + pointOne;
}
else
{
cout << "Nice, You got a Point!";
pointTwo = 1 + pointOne;
}
cout << "\n3. ";
cin >> numThree;
if (ansOne.find(numThree) == ansOne.end())
{
ansOne.erase(numThree);
cout << "Wrong!";
pointThree = 0 + pointTwo;
}
else
{
cout << "Nice, You got a Point!";
pointThree = 1 + pointTwo;
}
totalPoint = pointOne + pointTwo + pointThree;
cout << "\n" << totalPoint;
}
What I want to do is, if the answer is after they put the answers, and if the word is in there, I want to erase that word from the set so they can't duplicate the answer. But it's not getting erased from the set.
Per your declared logic, you put the erase in the wrong branch of the if, only erasing a word when the word wasn't in the set already, and not erasing it when it was. The first if/else block would be fixed with:
if (ansOne.find(numOne) == ansOne.end())
{
// Removed ansOne.erase(numOne); here, because you just confirmed it's not in ansOne
cout << "Wrong!";
pointOne = 0;
}
else
{
ansOne.erase(numOne); // It's in ansOne, remove it so it can't be guessed again
cout << "Nice, You got a Point!";
pointOne = 1;
}
Similar changes would be made to the other two if/else blocks.
Note that this code would be much simpler with a for loop that runs three times and maintains the running total, rather than individual variables for each of three nearly identical tests. For example, the fixed version of your code could simplify to:
int main()
{
string userinput; // Just one string for input
int totalPoints = 0; // Just one score counter
set<string> ansOne = { "TOE", "TONGUE", "TOOTH" };
cout << "Give A Body Part That Starts With The Letter T";
for (int i = 1; i <= 3; ++i) {
cout << '\n' << i << ". "; // Number prompts dynamically
cin >> userinput;
const auto inputloc = ansOne.find(userinput); // Storing off iterator speeds erasure later (admittedly not meaningful for three element set
if (inputloc == ansOne.end())
{
cout << "Wrong!";
}
else
{
ansOne.erase(inputloc); // Erase with iterator to element found
cout << "Nice, You got a Point!";
++totalPoints;
}
}
cout << '\n' << totalPoint << '\n';
}

How do I my Program to stop Replicating if wrong input

My program will repeat output: "You are currently on the 2 floor out of 5
The sum of the codes is: 7 and the product of the codes is: 12
Try again before he catches onto you!"
Based on how many wrong characters are added how can I fix this? I have inserted the cin.clear and cin.ignore but it will repeat the part above.
i.e. if I type wasds it will repeat 5x. Any other notes are also appreciated.
#include <iostream>
#include <ctime>
using namespace std;
int PlayerLevel = 0;
int MaxLevel = 5;
bool GamePlay ()
{
srand(time(NULL));
int PlayerGuessA, PlayerGuessB, PlayerGuessC;
int CodeA = rand() % PlayerLevel + PlayerLevel;
int CodeB = rand() % PlayerLevel + PlayerLevel;
int CodeC = rand() % PlayerLevel + PlayerLevel;
int SumofCodes = CodeA + CodeB + CodeC;
int ProductofCodes = CodeA * CodeB * CodeC;
cout << "You are currently on the " << PlayerLevel << " floor out of 5" << endl;
cout << "The sum of the codes is: " << SumofCodes << " and the product of the codes is: " << ProductofCodes << endl;
cin >> PlayerGuessA >> PlayerGuessB >> PlayerGuessC;
int PlayerProduct = PlayerGuessA * PlayerGuessB * PlayerGuessC;
int PlayerSum = PlayerGuessA + PlayerGuessB + PlayerGuessC;
if (PlayerProduct == ProductofCodes && SumofCodes == PlayerSum) {
cout << "Great Job you got this!!!\n" << endl;
++PlayerLevel;
return true;
}
else
{
cout << "Try again before he catches onto you!\n" << endl;
return false;
}
}
int GameStart()
{
string Introduction = "Welcome to your worst nightmare. You are trapped in a murderer's house. You are on the 5th floor and need to get to the first floor to escape.\n";
string Instructions = "He has each door locked behind a security system that requires a 3 number code to disarm it.\nEnter the codes and move foward. Each level will the code will be harder to figure out.\n";
string PlayerStart;
cout << Introduction << endl;
cout << Instructions << endl;
cout << "Would you like to escape? Yes or No" << endl;
cin >> PlayerStart;
if (!(PlayerStart != "Yes" && PlayerStart != "yes")) {
++PlayerLevel;
}
return 0;
}
int main ()
{
if (PlayerLevel == 0) {
GameStart();
}
while (PlayerLevel <= MaxLevel)
{
bool bLevelComplete = GamePlay();
cin.clear ();
cin.ignore();
}
cout << "You Made it out! Now run before he finds out!" << endl;
return 0;
}
When the type of the input doesn't match the type of the variable that it is being extracted to, cin sets the fail bit. Once this happens, all subsequent reads fail until the stream is reset. The offending characters are still left in the buffer, so that needs to be cleared out as well.
Your usage of cin.clear() and cin.ignore() meant that the fail bit was getting reset, but only one offending character was being removed (cin.ignore() ignores one character by default). This is why you saw the output repeating x times for x erroneous characters.
You could do something like this:
while (PlayerLevel <= MaxLevel)
{
bool bLevelComplete = GamePlay();
if (cin.fail())
{
//Input extraction failed, need to reset stream and clear buffer until newline
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}
}

How to Accept [ENTER] key as an invalid input and send out error message

This is a program that grade user inputs for the questions of Driver's License Exam.
I'm having trouble of validating the user input.
I'd like to accept the [ENTER] key as an invalid input and proceed to my validation rather than just go to an empty line and cannot process to the next question. Purpose is to send out error message and that no input is given and [ENTER] key is not valid input and only accept one more chance to enter valid input which are a/A, b/B, c/C, or d/D. So that is why I'm using if statement here instead of loop.
I tried if (testTakerAnswers[ans] == (or =) '\n') {} but still doesn't solve the problem of newline.
I include curses.h in here hope to use getch() statement from the other post but somehow I can't manage to work in my code with an array instead of regular input.
I'm looking for other methods as well rather than getch()
So should I adjust my bool function, or directly validate input in main() function.
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <curses.h>
using namespace std;
const unsigned SIZE = 20; // Number of qns in the test
char testTakerAnswers[SIZE]; //Array to hold test taker's answers
bool validateInput(char);
class TestGrader
{
private:
char answers[SIZE]; // Holds the correct answers // Answer is array
int getNumWrong (char[]);
void missedQuestions (char[]);
public:
void setKey(string); // Initialize object with standard keys
void grade(char[]); // Grades the answers from tester
};
void TestGrader::setKey(string key){
if (key.length()!=SIZE){
cout << "Error in key data.\n";
return;
}
for (unsigned pos = 0; pos < SIZE ; pos ++)
answers [pos] = key [pos];
}
void TestGrader::grade(char test[])
{
int numWrong = getNumWrong(test);
if (numWrong <= 5)
cout << "Congratulations. You passed the exam.\n";
else
cout << "You did not pass the exam. \n";
cout << "You got " << (SIZE-numWrong) << " questions correct. \n";
if (numWrong > 0){
cout << "You missed the following " << numWrong << " questions: \n";
missedQuestions(test);
}
}
int TestGrader::getNumWrong(char test[])
{
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
counter++;
}
}
return counter;
}
void TestGrader::missedQuestions(char test[])
{
// cout << testTakerAnswers[i]; This is to print taker's answers
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
cout << "\n" << i + 1 << ". Correct answers: " << answers[i];
counter++;
}
}
}
bool validateInput(char ans){ // Only A, B, C, D valid input
if (toupper(ans)!='A' && toupper(ans)!= 'B' && toupper(ans)!='C' && toupper(ans)!= 'D'){
cout << "\n********************WARNING*******************\n";
cout << "Invalid input! Enter only a/A, b/B, c/C, or d/D\n";
return false;
}
if (testTakerAnswers[ans] == '\n'){
return false;
}
return true;
}
int main()
{
const int NUM_QUESTIONS = 20;
string name; //Test taker's name
char doAnother; //Control variable for main processing loop
TestGrader DMVexam; //Create a TestGrader object
DMVexam.setKey("BDAACABACDBCDADCCBDA");
do {
cout << "Applicant Name: ";
getline(cin,name);
cout << "Enter answer for " << name << ".\n";
cout << "Use only letters a/A, b/B, c/C, and d/D. \n\n";
for (int i = 0; i < NUM_QUESTIONS; i++){
// Input and validate it
do{
cout << "Q" << i+1 << ": ";
cin >> testTakerAnswers[i];
if (!validateInput(testTakerAnswers[i])){
cout << "You get one more chance to correct.\nOtherwise, it count as wrong answer.";
cout << "\n*********************************************";
cout << "\nRe-enter: ";
cin >> testTakerAnswers[i];
cout << '\n';
break;
}
}while(!validateInput(testTakerAnswers[i]));
}
//Call class function to grade the exam
cout << "Results for " << name << '\n';
DMVexam.grade(testTakerAnswers);
cout << "\nGrade another exam (Y/N)? ";
cin >> doAnother;
while (doAnother != 'Y' && doAnother != 'N' && doAnother != 'y' && doAnother != 'n'){
cout << doAnother << " is not a valid option. Try Again y/Y or n/N" << endl;
cin >> doAnother;}
cout << endl;
cin.ignore();
}while(doAnother != 'N' && doAnother != 'n');
return 0;
}
Your issue is cin >> testTakerAnswers[i]; cin is whitespace delimited, that means that any whitespace (including '\n') will be discarded. So testTakerAnswers[i] can never be '\n'.
I'm not sure exactly what you want to do, but possibly try
getline(cin,input_string);
then
input_string == "A" | input_string == "B" | ...
So if only the enter key is pressed, input_string will become "".

Can't run my code though a loop however manually copying and pasting works

This bit of code works. I can also copy paste from start to end several times inside my main and it will still work.
int main()
{
string str;
cout << "Input a palindrome: "; // Start
getline(cin, str);
if (testPalindrome(str) == 1)
cout << "Your input is a palindrome: True" << endl;
else
cout << "Your input is a palindrome: False" << endl;
cout << endl; // End
cout << "\nCreated by,\nNorman Ettedgui" << endl;
system("pause");
return 0;
}
However this bit of code will not work and the error I get is a strings out of bound within my function (oddly enough before the function call).
This is my testPalindrome function:
bool testPalindrome(string str)
{
string newStr;
for (int i = 1; i < str.length() - 1; i++)
newStr += str[i];
if (newStr.length() > 1)
testPalindrome(newStr);
if (str[0] == str[str.length() - 1])
return true;
}
This is what I'm trying to run:
int main()
{
string str;
int i = 0;
while (i != -1)
{
cout << "Input a palindrome: ";
getline(cin, str);
if (testPalindrome(str) == 1)
cout << "Your input is a palindrome: True" << endl;
else
cout << "Your input is a palindrome: False" << endl;
cout << "-1 to Exit or any other number to continue: ";
cin >> i;
cout << endl;
}
cout << "\nCreated by,\nNorman Ettedgui" << endl;
system("pause");
return 0;
}
Try the following function
bool testPalindrome( string s)
{
return ( s.size() < 2 ? true
: s.front() == s.back() && testPalindrome( s.substr( 1, s.size() -2 ) ) );
}
Also in main substitute this statement
if (testPalindrome(str) == 1)
for
if ( testPalindrome(str) )
If you use getline and operator >> simultaneously then you should use ignore to skip ENTER key
(DO not forget include <limits>)
#include <limits>
while (i != -1)
{
cout << "Input a palindrome: ";
cin.ignore( numeric_limits<streamsize>::max() );
getline(cin, str);
//...
cin >> i;
cout << endl;
}
I will explain you why you got the error. Without statement with the call of ignore function getline read an empty string. So str was empty. In function testPalindrome there is statement
for (int i = 1; i < str.length() - 1; i++)
As for an empty string its length is equal to 0 then expression
str.length() - 1
has the maximum value for the unsigned type because the type of this expression is some unsigned integral type and the internal representation of -1 corresponds to the maximim unsigned value.
So variable i will be always less than -1 and you get memory access violation.
Also I would use another loop without using additional variable i.
while ( true )
{
cout << "Input a palindrome: ";
string str;
getline(cin, str);
if ( str.empty() ) break;
//...
}
if (newStr.length()>1) only handles the condition when newStr.length() is >1. You need an else statement to handle when the condition: if (newStr.length()>1) is false.

Cannot input more than one string in palindrome program

#include <iostream>
#include <ctype.h>
using namespace std;
void isPalindrome();
int main()
{
char response;
isPalindrome();
cout << "Input another string(y/n)?" << endl;
cin >> response;
response = toupper(response);
if (response == 'Y')
isPalindrome();
return 0;
}
void isPalindrome()
{
char str[80], str2[80];
int strlength;
int j = 0;
int front, back;
bool flag = 1;
cout << "Input a string:" << endl;
cin.getline(str, 80);
strlength = strlen(str);
for (int i = 0; i < strlength; i++)
{
if (islower(str[i]))
str[i] = toupper(str[i]);
}
for (int i = 0; i < strlength; i++)
{
if (isalpha(str[i]))
{
str2[j] = str[i];
j++;
}
}
str2[j] = '\0';
front = 0;
back = strlength - 1;
for (int i = 0; i < j / 2; i++)
{
if (str2[front] != str2[back])
{
flag = 0;
break;
}
}
if (!(flag))
cout << "It is not a palindrome" << endl;
else
cout << "It's a palindrome" << endl;
cout << "str: " << str << " str2: " << str2 << " strlength: " << strlength << " j: " << j << endl;
cout << "front: " << front << " back: " << back << " flag: " << flag << endl;
}
I was just wondering if anybody could help explain to me why my code isn't working.
I can run it once just fine and I get the right answer, but when the prompt asks if I want to input another string and I type 'y', the prompt just skips over the input and terminates on it's own.
I tried cin.ginore('\n', 80), but that just gave me a bunch of blank lines. I added the bit of code at the end to check the values and they all go to 0 and drop the strings.
Maybe a link to a proper explanation of how the system handles memory?
edit:
I keep getting the same problem when running the input sequence a second time. The output looks like this:
Input a string:
Radar
It's a palindrome
Input another string(y/n)?
y
_ <- this being my cursor after pressing enter 3 times
I'll just re-build the program from scratch and try to do it without a function. I'd still appreciate a link to a page that explains how to process user input using modern c++.
The problem is with:
cin >> response;
This reads the user input y/n into the variable response but a newline is left in the input buffer which is picked by the getline function the isPalindrome function.
To fix this you need to remove the newline from the input buffer after you read the user response. You do it by using:
cin >> response;
std::cin.ignore(INT_MAX);
With the above fix you can retry the palindrome check just once. To make multiple retries possible you'll need a loop. I would recommend a do-while loop in your main as:
char response;
do {
isPalindrome();
cout << "Input another string(y/n)?" << endl;
cin >> response;
std::cin.ignore(INT_MAX);
response = toupper(response);
} while(response == 'Y');
You need a loop. There's no code that instructs the program to go back to the top.
char response = 'Y';
while (response == 'Y') {
isPalendrome();
cout << "Input another string(y/n)?" << endl;
cin >> response;
}
This isn't your entire program, just key elements that you need for a while loop. You should get an understanding of how while works and make this work for your program.
In contemporary C++ one would typically use standard library components for string processing:
#include <iostream>
#include <string>
int main()
{
std::string line1, line2, response;
do
{
std::cout << "First string: ";
if (!std::getline(std::cin, line1)) { /* error */ }
std::cout << "Second string: ";
if (!std::getline(std::cin, line2)) { /* error */ }
// check line1 and line2 for palindromy
std::cout << "Again (y/n)? ";
std::getline(std::cin, response);
} while (std::cin && (response == "y" || response == "Y"));
}