HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Ask the user random questions from a multiple-choice test

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
randomtheuseraskquestionschoicetestmultiplefrom

Problem

I'm quite new to programming and was hoping you wouldn't mind taking a look at my code and giving some points as to how I could clean it up.

Assignment guidelines:


Create a program that reads multiple choice questions from 1 file and
gives 10 random questions to the user. Do Not uses classes.

Example of how the questions are stored in the text document I created

  • Question (end of line)



  • Option1 (end of line)



  • Option2 (end of line)



  • Option3 (end of line)



  • Option4 (end of line)



  • Answer (end of line)



  • (intentionally left blank)



  • Question2...Question20 (rinse and repeat for remaining questions)



Code I used:

```
#include
#include
#include
#include

using namespace std;

struct questionFormat
{
string question;
string answersA;
string answersB;
string answersC;
string answersD;
string answerSheet;
string space;
};

int main ()
{
questionFormat q;
string questions [20];
string answersA [20];
string answersB [20];
string answersC [20];
string answersD [20];
string answerSheet [20];
string space[20];
int userAnswer [10];
int testQuestions [10] = {99,99,99,99,99,99,99,99,99,99};
int counter = 0, num = 0, userCorrect =0, correctAnswer = 0;
fstream infile("testQuestions.txt", ios::in);
srand(time(NULL));

do
{
getline (infile, q.question);
questions[counter] = q.question;

getline (infile, q.answersA);
answersA[counter] = q.answersA;

getline (infile, q.answersB);
answersB[counter] = q.answersB;

getline (infile, q.answersC);
answersC[counter] = q.answersC;

getline (infile, q.answersD);
answersD[counter] = q.answersD;

getline (infile, q.answerSheet);
answerSheet[counter] = q.answerSheet;

getline (infile, q.space);
space[counter] = q.space;

counter++;
} while (counter > userAnswer[counter];

correctAnswer = stoi(answ

Solution

Cleanup questionFormat

  • You don't need the space variable.



  • The variables answersA, etc. should be answerA, etc.



  • The type of answerSheet can be int. I also think that correctAnswer is a better name for the member.



struct questionFormat
{
   string question;
   string answerA;
   string answerB;
   string answerC;
   string answerD;
   int correctAnswer;
};


Use an array of questionFormat instead of many arrays of strings

The lines

string questions [20];
string answersA [20];
string answersB [20];
string answersC [20];
string answersD [20];
string answerSheet [20];
string space[20];


can be replaced by

questionFormat questions[20];


Create function for reading data

Create function readData and move the code to read the data from main to readData.

int readData(std::string const& inputFile,
              questionFormat questions[],
              int maxQuestions)
{
   fstream infile("testQuestions.txt", ios::in);
   ...
}


Don't assume file IO succeeded

Always check status of file IO operations. It's never safe to assume that they succeeded.

Change the lines that read the input to:

for (counter = 0; counter > q.correctAnswer ) )
   {
      std::cout ::max(), '\n');
   infile.ignore(std::numeric_limits::max(), '\n');
}


Simplify the find line

The line

if (bool exists = find(begin(testQuestions), end(testQuestions), num) != end(testQuestions))


can be simplified to:

if (find(begin(testQuestions), end(testQuestions), num) != end(testQuestions))


Move the code to conduct the tests to a separate function

void conductTests(questionFormat questions[],
                  int maxQuestions)
{
   ...
}


The contents of conductTests will be different from your posted code due to use of an array of questionFormat to hold the data.

That will simplify main to:

int main ()
{
   questionFormat questions[20];

   srand(time(NULL));

   int numQuestions = readData("testQuestions.txt", questions, 20);

   conductTests(questions, numQuestions);

   return 0;
}


No need to use an array for userAnswer

The value is read and used inside every iteration of the loop. It can be a simple int. Not only that, it can be in the scope of the while loop instead of being in the function scope.

Here's the complete program:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

struct questionFormat
{
   string question;
   string answerA;
   string answerB;
   string answerC;
   string answerD;
   int correctAnswer;
};

int readData(std::string const& inputFile,
             questionFormat questions[],
             int maxQuestions)
{
   fstream infile("testQuestions.txt", ios::in);

   for (int counter = 0; counter ::max(), '\n');
      infile.ignore(std::numeric_limits::max(), '\n');
   }

   return maxQuestions;
}

void conductTests(questionFormat questions[],
                  int maxQuestions)
{
   int testQuestions [10] = {99,99,99,99,99,99,99,99,99,99};
   int counter = 0;
   int userCorrect = 0;

   cout > userAnswer;

         if (userAnswer == questions[num].correctAnswer)
         {
            userCorrect++;
         }
         counter++;
      }
   }

   cout << "You got a total of " << userCorrect << " out of 10 correct" << endl;
}

int main ()
{
   questionFormat questions[20];

   srand(time(NULL));

   int numQuestions readData("testQuestions.txt", questions, 20);

   conductTests(questions, numQuestions);

   return 0;
}

Code Snippets

struct questionFormat
{
   string question;
   string answerA;
   string answerB;
   string answerC;
   string answerD;
   int correctAnswer;
};
string questions [20];
string answersA [20];
string answersB [20];
string answersC [20];
string answersD [20];
string answerSheet [20];
string space[20];
questionFormat questions[20];
int readData(std::string const& inputFile,
              questionFormat questions[],
              int maxQuestions)
{
   fstream infile("testQuestions.txt", ios::in);
   ...
}
for (counter = 0; counter < maxQuestions; ++counter )
{
   questionFormat& q = questions[counter];

   if ( !getline (infile, q.question) )
   {
      std::cout << "Failed to read a question.\n";
      return counter;
   }

   if ( !getline (infile, q.answerA) )
   {
      std::cout << "Failed to read answer A to a question.\n";
      return counter;
   }

   if ( !getline (infile, q.answerB)  )
   {
      std::cout << "Failed to read answer B to a question.\n";
      return counter;
   }

   if ( !getline (infile, q.answerC) )
   {
      std::cout << "Failed to read answer C to a question.\n";
      return counter;
   }

   if ( !getline (infile, q.answerD) )
   {
      std::cout << "Failed to read answer D to a question.\n";
      return counter;
   }

   if ( !(infile >> q.correctAnswer ) )
   {
      std::cout << "Failed to read the correct answer to a question.\n";
      return;
   }

   // Ignore two lines of text.
   // The first line corresponds to what's left in the stream
   // after reading the correct answer.
   // The second line is the intentionally left space.
   infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
   infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Context

StackExchange Code Review Q#141115, answer score: 7

Revisions (0)

No revisions yet.