Help with a program.please

Last Edited By Krjb Donovan
Last Updated: Mar 12, 2014 02:46 PM GMT

Question

QUESTION: Here is my Program.Basically It does everything i want it to do , except check for data errors. I got the one to work for the " ivalid ticket type" but I need it to check the rows and the seats..Also my " cout << "This seat already assigned. Choose another seat: " creates an infinite loop and I dont know why ..Thank you in advance

  1. include<iostream>
  2. include<cctype>
  3. include<iomanip>

using namespace std;

void initialize(char form[][6]); void getData(char& ticketType, int& row,

            char& column);

void printForm(char form[][6], int row, char column);

int main() {

   char ch, ticketType, column;
   int row;
   char form[13][6];
   
   initialize(form);
   cout << "This program allows the user to assign seats to an airplane."
        << "\n\nDo you wish to begin the seating assignments? Y/y for yes or N/n for no." << endl;
    cin >> ch;
   
   ch = static_cast<char>(toupper(ch));
   while(ch == 'Y')     
   { 
       getData(ticketType, row, column);
       printForm(form, row, column);
                
       cout << "Continue with the seating assignments? Y/y for yes or N/n for no." << endl;
       cin >> ch;
       ch = static_cast<char>(toupper(ch));
       if(ch == 'N')
         return 0;     
   }  
   
   return 0;

}

void initialize( char form[][6]) {

    for(int i=0 ;i < 13 ;i++)
      for(int j=0 ;j<6 ;j++)
        form[i][j]='*';

}


void getData(char& ticketType, int& row, char& column) {

   cout << "\nThe airplane has 13 rows, with six seats in each row. " << endl;
          
   cout << "Please Enter ticket type,\n"
        << "F for first class, \n"
        << "B for business class,\n"
        << "E for economy class:" << endl;
   cin >> ticketType;
   ticketType = static_cast<char>(toupper(ticketType));
   while(ticketType != 'F' && ticketType != 'B' 
         && ticketType && ticketType != 'E')
   {
       cout << "Invalid ticket type." << endl;
       cout << "Enter ticket type,\n"
            << "F for first class, \n"
            << "B for business class,\n"
            << "E for economy class:" << endl;
       cin >> ticketType;
       ticketType = static_cast<char>(toupper(ticketType));
    }      
   switch(ticketType)
   {
          case 'F':
               cout <<  "Row 1 and 2 are first class,\n" ;
               break;
          case 'B':
               cout <<  "row 3 throuh 7 are business class,\n";
               break;
          case 'E':
               cout <<  "row 8 through 13 are economy class." << endl; 
               break;
   }// end switch
               
   cout << "Enter the row number you want to sit: " << endl ;
   cin >> row;  

{

   cout << "Enter the seat number (from A to F). " << endl;
   

cin >> column;

   column = static_cast<char>(toupper(column));
   }
   

}

void printForm(char form[][6], int row, char column) {

   int i, j;
 
   if(form[row-1][static_cast<int>(column-65)]=='X')
  {
      cout << "This seat already assigned. Choose another seat: " << endl;
      cin >> column;
      column = static_cast<char>(toupper(column));  
  }  
   form[ row-1 ] [static_cast<int>(column)-65]= 'X';
   
   cout << "* indicates that the seat is available; " << endl; 
   cout << "X indicates that the seat is occupied. " << endl;
   cout << setw(12) << "A" << setw(6) << "B" << setw(6) << "C" 
        << setw(6) << "D" << setw(6) << "E" << setw(6) << "F" << endl;
        
   for(i = 0; i < 13; i++)
   {
      cout << left << setw(3) << "Row " << setw(2)<< i+1 ;
      for(j = 0; j < 6; j++)
      {
         cout << right  << setw(6) << form [i][j];
      }
      cout << endl;
   }

}

ANSWER: Hello Jason. The infinite loop comes with cin >> someInteger when you accidentally enter a character. Input can be done into a string, and then the string examined for data. I believe that is a better way. My comments in the code explain it more.

I understand that you wanted error checking for all your prompts. I see you know how to do it because you did it with ticketType. However, your coding can be made cleaner and easier by putting the input code in to a re-usable function. Have a look at how I did it. I have some other comments in the code for you to think about.

  1. include<iostream>
  2. include<cctype>
  3. include<iomanip>
  4. include<string>

using namespace std;

void initialize(char form[][6]); void getData(char& ticketType, int& row,

            char& column);

void printForm(char form[][6], int row, char column);

/* Input is tricky. When you do cin >> character, the character typed is input but there is the newline waiting in the input buffer which may cause problems in subsequent cin calls. Input should always be done by std::getline into a std::string This guarantees that the entire input line is read and the keyboard buffer is cleared. You don't have to worry about buffer overflow, because the string takes care of allocating enough memory to read the line

  • /

char inputChar(const char* prompt, const char* valid) {

   char result;
   do 
   {
       cout << prompt << endl;
       std::string text;
       std::getline(cin, text);
       result = text[0];
       result = static_cast<char>(toupper(result));
   } while(strchr(valid, result) == NULL);
   return result;

}

int inputInt(const char* prompt, int lowValid, int highValid) {

   int result;
   do
   {
       cout << prompt << endl;
       std::string text;
       std::getline(cin, text);
       result = atoi(text.c_str());
   } while (result < lowValid || result > highValid);
   return result;

}

int main() {

   char ch, ticketType, column;
   int row;
   char form[13][6];
   initialize(form);
   ch = inputChar("This program allows the user to assign seats to an airplane."
       "\n\nDo you wish to begin the seating assignments? Y/y for yes or N/n for no.", "YN");
   while(ch == 'Y')     
   {
       getData(ticketType, row, column);
       printForm(form, row, column);
       ch = inputChar("Continue with the seating assignments? Y/y for yes or N/n for no.", "YN");
   }  
   return 0;

}

void initialize( char form[][6]) {

   for(int i=0 ;i < 13 ;i++)
       for(int j=0 ;j<6 ;j++)
           form[i][j]='*';

}


void getData(char& ticketType, int& row, char& column) {

   cout << "\nThe airplane has 13 rows, with six seats in each row. " << endl;
   ticketType = inputChar("Please Enter ticket type,\n"
       "F for first class, \n"
       "B for business class,\n"
       "E for economy class:", 
       "FBE");
   switch(ticketType)
   {
   case 'F':
       cout <<  "Row 1 and 2 are first class,\n" ;
       break;
   case 'B':
       cout <<  "row 3 throuh 7 are business class,\n";
       break;
   case 'E':
       cout <<  "row 8 through 13 are economy class." << endl;
       break;
   }// end switch
   /* This inputInt call restricts input to be from 1 through 13
   Perhaps it should be further restricted based on ticketType
   */
   row = inputInt("Enter the row number you want to sit: ", 1, 13);
   /* What if the row is already full ? Should the user even be allowed to 
   go to the next step ?
   */
   column = inputChar("Enter the seat number (from A to F). ", "ABCDEF");

}

/* printForm should do just one thing, that is print the form showing available seats it should not do input. It would be nice if the form of available seats was printed before asking the user for a seat choice.

  • /

void printForm(char form[][6], int row, char column) {

   int i, j;
   /*
   This user input should not be in printForm, and the "if" should be a "while" 
   so that the user needs to choose another column until a valid one is chosen
   */
   // using column - 'A' instead of column-65 make the purpose more obvious
   /* if */ while(form[row-1][static_cast<int>(column-65)]=='X') 
   {
       cout << "This seat already assigned. Choose another seat: " << endl;
       cin >> column;
       column = static_cast<char>(toupper(column));  
   }  
   form[ row-1 ] [static_cast<int>(column)-65]= 'X';
   cout << "* indicates that the seat is available; " << endl;
   cout << "X indicates that the seat is occupied. " << endl;
   cout << setw(12) << "A" << setw(6) << "B" << setw(6) << "C"
       << setw(6) << "D" << setw(6) << "E" << setw(6) << "F" << endl;
   for(i = 0; i < 13; i++)
   {
       cout << left << setw(3) << "Row " << setw(2)<< i+1 ;
       for(j = 0; j < 6; j++)
       {
           cout << right  << setw(6) << form [i][j];
       }
       cout << endl;
   }

}

---------- FOLLOW-UP ----------

QUESTION: I understand a little what you did. But I have a few questions.

Im not following what you mean by using column - 'A' instead of column-65 make the purpose more obvious.

Also, how do I restrict row numbers ..meaning if you want first class..you cant enter row 5

and one more .. Iwould like the program if you do enter the wrong input it tells you it inavlid ..

Thank you!

ANSWER: Hello Jason

>Im not following what you mean by using column - 'A' instead of column-65 make the purpose more obvious. 65 is the character code for 'A'. In the program you have columns A through F. You subtract 65 from the column so that you can have numbers from 0 through 5. The numbers are then used to index an array. It seems more clear to me to say column - 'A' instead of column - 65, because you are subtracting off the value of 'A'. It's a style thing. If you don't like it, don't worry about it.


>Also, how do I restrict row numbers ..meaning if you want first class..you cant enter row 5 How about in switch(ticketType), decide what the low and high row values are, then instead of calling row = inputInt("Enter the row number you want to sit: ", 1, 13); use the calculated low and high values instead of 1, and 13

>and one more .. Iwould like the program if you do enter the wrong input it tells you it inavlid ..

How about something like this. I've added the "firstPrompt" flag. Does it make sense to you ?

char inputChar(const char* prompt, const char* valid) {

  char result;
  bool firstPrompt = true;
  do
  {
      if (! firstPrompt)
      {
           cout << "That was an invalid value\n";
      }
      cout << prompt << endl;
      firstPrompt = false;
      std::string text;
      std::getline(cin, text);
      result = text[0];
      result = static_cast<char>(toupper(result));
  } while(strchr(valid, result) == NULL);
  return result;

}

You can do the same in inputInt

---------- FOLLOW-UP ----------

QUESTION: Please pardon the ignorance, and I sincerely appreciate your help..

But can you show me an example of how to write this

Also, how do I restrict row numbers ..meaning if you want first class..you cant enter row 5 How about in switch(ticketType), decide what the low and high row values are, then instead of calling row = inputInt("Enter the row number you want to sit: ", 1, 13); use the calculated low and high values instead of 1, and 13

Answer

Hello Jason.

Sorry that I did not make it clear.

For restricting row numbers, try this modified version of the getData function. Look at how I'm setting and using the new rowLow and rowHigh variables.

void getData(char& ticketType, int& row, char& column) {

   cout << "\nThe airplane has 13 rows, with six seats in each row. " << endl;
   ticketType = inputChar("Please Enter ticket type,\n"
       "F for first class, \n"
       "B for business class,\n"
       "E for economy class:",
       "FBE");
   int rowLow;
   int rowHigh;
   switch(ticketType)
   {
   case 'F':
       cout <<  "Row 1 and 2 are first class,\n" ;
       rowLow = 1;
       rowHigh = 2;
       break;
   case 'B':
       cout <<  "row 3 throuh 7 are business class,\n";
       rowLow = 3;
       rowHigh = 7;
       break;
   case 'E':
       cout <<  "row 8 through 13 are economy class." << endl;
       rowLow = 8;
       rowHigh = 13;
       break;
   }// end switch
   row = inputInt("Enter the row number you want to sit: ", rowLow, rowHigh);
   column = inputChar("Enter the seat number (from A to F). ", "ABCDEF");

}

Advertisement

©2021 eLuminary LLC. All rights reserved.