-2

I am trying to code exception handling in my switch statement for a memnu in case user inputs something other than an int. Tried many different methods and still get continuous loop when user inputs a character.

I have tried using std exception but even with the include my compiler still sees error during build.

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace std;

class Exam

{

public:

    int loadExam()
    {

        //ifstream infile;
        //string examName = exam;
        ifstream infile("exam.txt");
        streambuf *cinbuf = cin.rdbuf();       //save old buf
        cin.rdbuf(infile.rdbuf());             //redirect std::cin to infile.txt!

        string line, theQuestion, questiontype, theAnswer;
        int  questionvalue;

        //get the number of questions from the first line in the file
        getline(cin,line);
        numquestions = atoi(line.c_str());
        for(int count = 0; count < numquestions; count++){

            getline(cin,line);

            //get the next line with the question type and the value of the question
            int npos = line.size();
            int prev_pos = 0;
            int pos = 0;

            while(line[pos]!=' ')

                pos++;

            questiontype = line.substr(prev_pos, pos-prev_pos);
            prev_pos = ++pos;
            questionvalue = atoi(line.substr(prev_pos, npos-prev_pos).c_str()); // Last word

            //process a true/false question
            if (questiontype == "TF")
            {

                myQuestions[count] = new QuestionTF;
                getline(cin,theQuestion);
                myQuestions[count]->setQuestion(theQuestion,questionvalue);

            }

            //process a multiple choice question
            if (questiontype == "MC")
            {

                myQuestions[count] = new QuestionMC;
                getline(cin,theQuestion);
                myQuestions[count]->setQuestion(theQuestion,questionvalue);

            }
        }

        cin.rdbuf(cinbuf);   //restore cin to standard input
        return numquestions;

    }

    void displayExamQuestions(int numquestions)
    {

        string qtype;

        //print out the questions that have been processed
        for(int count = 0; count<numquestions;count++)

        {

            qtype = myQuestions[count]->getQuestionType();
            cout << qtype << " " << myQuestions[count]->getValue() << "\n";
            myQuestions[count]->printOptions();
            cout << "\n";

        }
    }

private:

    Question *myQuestions[10];
    int numquestions;

};

int main() {

    Exam myExam;
    int numquestions;
    int choice;

    while((choice = displayMenu())!=3)

        switch(choice)
        {
            case 1:
                numquestions = myExam.loadExam();
                break;

            case 2:
                myExam.displayExamQuestions(numquestions);
                break;

            default:
                cout << "Invalid choice.  Try again.\n\n";

        }

   getchar();
    return 0;

}

int displayMenu()
{

    int choice;

    cout << "\t===================== Exam Menu =====================" << endl;
    cout << "\t1.  Load Exam "<<endl;
    cout << "\t2.  Display Exam "<<endl;
    cout << "\t3.  Quit"<<endl;
    cout << "\t=====================================================" << "\n" << endl;
    cout << "Please enter your selection: ";
    cin >> choice;
    cout << "\n" << endl;

    return choice;

}

Require output to read "Invalid selection, Please try again" when a user inputs a character or string of alpha characters.

  • What exactly do you mean by exceptions? What do you expect out of `std::exception`? – François Andrieux Sep 07 '19 at 21:32
  • Don't use switches. Don't use exceptions to handle input errors. Don't write console-based menus. Do test if files open, and report errors if not. Do test the return value of every input function. In other words, don't write code like that which you have written. –  Sep 07 '19 at 21:33
  • If you get compiler errors, please copy and paste them here. If you get runtime erros, please add your inputs, output of your program and expected output. – Yksisarvinen Sep 07 '19 at 21:33
  • possible duplicate (if I understood correctly): https://stackoverflow.com/questions/26187729/stdcin-doesnt-throw-an-exception-on-bad-input – walnut Sep 07 '19 at 21:37

1 Answers1

0

In this case, validation should be handled by the displayMenu function for two reasons.

  1. The displayMenu function says that it will return an integer so it should be responsible for ensuring the user inputs a number, not a char or string.

  2. The displayMenu lists the options so it knows how many options are available, meaning it should also check that the integer is between 1 and 3.

Infinite loop with cin when typing string while a number is expected

    int displayMenu() //This function should be responsible for validating that an 
                      // int was inputed
    {
        int choice;

        while (true)
        {
            cout << "\t===================== Exam Menu =====================" << endl;
            cout << "\t1.  Load Exam " << endl;
            cout << "\t2.  Display Exam " << endl;
            cout << "\t3.  Quit" << endl;
            cout << "\t=====================================================" << "\n" << endl;
            cout << "Please enter your selection: ";
            cin >> choice;
            cout << "\n" << endl;

            if (cin.fail())
            {
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n'); //This clears out the stream if they entered a string
                //Try using cin.ignore() and inputing a string to see what happens.
            }
            else if (choice >= 1 && choice <= 3)
            {
                break;
            }
        }

        return choice;
    }

You could decouple this second part by having a displayMenu function that simply prints the menu and a second function called getInput that doesn't care what integer is inputed. It would then be up to the calling function to make sure the value is between 1 and 3.

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace std;

void displayMenu();
int getInput();

int main() {

    int numquestions;
    int choice = 0;

    while (choice != 3)
    {
        displayMenu();
        while ((choice = getInput()) < 1 || choice > 3) 
        {
            std::cout << "Please pick a value between 1 and 3\n";

            displayMenu();
        }

        switch (choice)
        {
        case 1:
            cout << "Case 1\n";
            break;

        case 2:
            cout << "Case 2\n";
            break;

        default:
            cout << "Invalid choice.  Try again.\n\n";
        }
    }

    getchar();
    return 0;

}

//Only responsible for getting an int
int getInput()
{
    int choice;

    while (true)
    {
        cin >> choice;
        cout << "\n" << endl;

        if (cin.fail())
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');

            std::cout << "Please enter a valid number\n";
        }
        else
        {
            break;
        }
    }

    return choice;
}

//This function only displays a menu
void displayMenu()
{
    cout << "\t===================== Exam Menu =====================" << endl;
    cout << "\t1.  Load Exam " << endl;
    cout << "\t2.  Display Exam " << endl;
    cout << "\t3.  Quit" << endl;
    cout << "\t=====================================================" << "\n" << endl;
    cout << "Please enter your selection: ";
}