0

i need to prevent the junk left in the buffer as entering a value for a switch case menu from being used in a function called by the menu where their is user input.

menu code

void menu()
{
bool done = false; 
string input;
while(!done)
{
    cout << "Welcome to the DVD database." << endl;
    cout << "1. Add A DVD" << endl;
    cout << "2. Delete a DVD." << endl;
    cout << "3. Edit a DVD." << endl;
    cout << "4. List By Category." << endl;
    cout << "5. Retrieve by a DVD by Title." << endl;
    cout << "6. Display collection by year" << endl;
    cout << "7. Display collection by title" << endl;
    cout << "-999. Exit program" << endl;
    cout << "Please choose an option by entering the corresponding number" << endl;
    cin >> input;
    int value = atoi(input.c_str());
    switch(value)
    {
        case 1:addDVD(); break;
        case 2:deleteDVD(); break;
       // case 3:editDVD(); break;
        case 4:listByCategory();break;
        case 6:displayByYear();break;
        case 7:displayByTitle();break;
        case -999: writeToFile(); exit(0); break;
        default : cout <<"Invalid entry"<< endl; break;
    }
}
}

void retrieveByTitle()
{
string search;
int size = database.size();
int index = 0;
bool found = false;
cin.ignore();
cout << "Please enter the title of the DVD you would like to retrieve: " << endl;
getline(cin,search);
cout << search;
while(!found && index<size)
{
    if(database.at(index)->getTitle().compare(search)==0)
    {
        cout << database.at(index)->toString();
        break;
    }
}
cout << endl;
}

if 5 is entered in the menu, the program skips the user input in the method

simonc
  • 41,632
  • 12
  • 85
  • 103
Robert Spratlin
  • 305
  • 3
  • 5
  • 8
  • Why do you read into a string and use atoi instead of just reading into a number? (int x; cin >> x;) – tohava Jan 13 '13 at 23:01
  • when i input 5 in the menu() method (to go to the retrieveByTitle() method, i am unable to input anything when requested by retrieveByTitle() becuase whatever is left in the buffer when i made the choice back in menu() was used when getline() is called in retrieveByTitle. – Robert Spratlin Jan 13 '13 at 23:02
  • What's left is `\n` (or Enter) you are pressing to read the input. So when the program asks you for title `getline()` reads as input a line break `\n`. You need to consider how to stop this... – Theocharis K. Jan 13 '13 at 23:04
  • @tohava, that is not such a bad idea, as it avoids choking with illegal inputs (cin >> anInteger errors out with an input of 'hi') – tucuxi Jan 13 '13 at 23:06
  • Consider flushing your `cin`, see this [question][1] [1]: http://stackoverflow.com/questions/257091/how-do-i-flush-the-cin-buffer – emartel Jan 13 '13 at 23:09
  • cause im having to take my implentation of this in java and convert it to c++ so staying as close as possible helps – Robert Spratlin Jan 13 '13 at 23:09
  • cin.clear(); cin.ignore(INT_MAX,'\n'); has no effect on what happens – Robert Spratlin Jan 13 '13 at 23:10
  • Maybe you have an error in `retrieveDVD()` function? – Theocharis K. Jan 13 '13 at 23:20
  • Consider reducing your code to the smallest self-contained sample that exhibits the problem (an SCCE), and editing your question so you only post that. – tucuxi Jan 13 '13 at 23:26
  • accepted best practice is to avoid mixing cin << and getline; they tend to interfere like this. – tucuxi Jan 13 '13 at 23:32

2 Answers2

0

This code works, but it has the same problem you describe if you eliminate the 'cin.ignore()', which removes the extra delimiters ignored by the cin >> operator:

#include <iostream>
#include <climits>
using namespace std;

int main() {
    string a, b;
    while (true) {

        cout << "write 'x' to exit: " << endl;
        cin >> a;
        if (a == "x") {
            break;
        }       
        cout << "read '" << a << "'" << endl;

        cout << "now write a line: " << endl;
        cin.clear();          // clears cin status
        cin.ignore(INT_MAX);  // clears existing, unprocessed input

        getline(cin, a);
        cout << "read '" << a << "'" << endl;
    }

    return 0;
}
tucuxi
  • 17,561
  • 2
  • 43
  • 74
0

When dealing with interactive user input you should use std::getline()

The std::cin is flushed to the application every time you hit <enter>. So this is the logical junks you should read data from the user in.

std::string answer;
std::cout << "Question:\n";
std::getline(std::cin, answer);

This gets you everything the user provided in response to the previous question.

Once you have the input you should get the value you think is on the input. Once you have this you should check if there is any other junk on the input (if there is then abort and re-try) otherwise validate the data you expected.

If you were expected an integer;

std::stringstream linestream(answer);
int               value;
std::string       junk;

if ((answer >> value)) && (!(answer >> junk)))
{
    // If you got data
    // and there was no junk on the line you are now good to go
}

In your specific example there is already a simple way to do this:

std::getline(std::cin, input);
int value = boost::lexical_cast<int>(input);  // throws an exception if there is not
                                              // an int on the input (with no junk)
Martin York
  • 257,169
  • 86
  • 333
  • 562