Ask the user random questions from a multiple-choice test 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 &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;cstring&gt;
#include &lt;iomanip&gt;

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 &lt; 20);

    cout &lt;&lt; "Welcome to my fantastic test.\nYou will randomly be given 10/20 questions." &lt;&lt; endl;

    counter = 0;

    while (counter &lt; 10)
    {
        num = rand()%20;
        cout &lt;&lt; "Current random number: " &lt;&lt; num &lt;&lt; endl;
        cout &lt;&lt; "Counter is: " &lt;&lt; counter &lt;&lt; endl;
        if (bool exists = find(begin(testQuestions), end(testQuestions), num) != end(testQuestions))
        {
            continue;
        }
        else
        {
            testQuestions[counter] = num;
            cout &lt;&lt; "\nQuestion # " &lt;&lt; counter +1 &lt;&lt; endl;    
            cout &lt;&lt; questions [num] &lt;&lt; endl;
            cout &lt;&lt; answersA [num] &lt;&lt; endl;
            cout &lt;&lt; answersB [num] &lt;&lt; endl;
            cout &lt;&lt; answersC [num] &lt;&lt; endl;
            cout &lt;&lt; answersD [num] &lt;&lt; endl;
            cin &gt;&gt; userAnswer[counter];

            correctAnswer = stoi(answerSheet[num]);
            if (userAnswer[counter] == correctAnswer)
            {
                userCorrect++;
            }
            counter++;
        }
    }
    cout &lt;&lt; "You got a total of " &lt;&lt; userCorrect &lt;&lt; " out of 10 correct" &lt;&lt; endl;

    return 0;
}
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&amp; 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 &lt; maxQuestions; ++counter )
{
   questionFormat&amp; q = questions[counter];

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

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

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

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

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

   if ( !(infile &gt;&gt; q.correctAnswer ) )
   {
      std::cout &lt;&lt; "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&lt;std::streamsize&gt;::max(), '\n');
   infile.ignore(std::numeric_limits&lt;std::streamsize&gt;::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 &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;cstring&gt;
#include &lt;iomanip&gt;
#include &lt;string&gt;
#include &lt;cstdlib&gt;
#include &lt;limits&gt;
#include &lt;algorithm&gt;

using namespace std;

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

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

   for (int counter = 0; counter &lt; maxQuestions; ++counter )
   {
      questionFormat&amp; q = questions[counter];

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

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

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

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

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

      // 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&lt;std::streamsize&gt;::max(), '\n');
      infile.ignore(std::numeric_limits&lt;std::streamsize&gt;::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 &lt;&lt; "Welcome to my fantastic test.\nYou will randomly be given 10/20 questions." &lt;&lt; endl;

   while (counter &lt; 10)
   {
      int userAnswer;
      int num = rand()%maxQuestions;
      cout &lt;&lt; "Current random number: " &lt;&lt; num &lt;&lt; endl;
      cout &lt;&lt; "Counter is: " &lt;&lt; counter &lt;&lt; endl;
      if (find(begin(testQuestions), end(testQuestions), num) != end(testQuestions))
      {
         continue;
      }
      else
      {
         testQuestions[counter] = num;
         cout &lt;&lt; "\nQuestion # " &lt;&lt; counter +1 &lt;&lt; endl;    
         cout &lt;&lt; questions [num].question &lt;&lt; endl;
         cout &lt;&lt; questions [num].answerA &lt;&lt; endl;
         cout &lt;&lt; questions [num].answerB &lt;&lt; endl;
         cout &lt;&lt; questions [num].answerC &lt;&lt; endl;
         cout &lt;&lt; questions [num].answerD &lt;&lt; endl;
         cin &gt;&gt; userAnswer;

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

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

int main ()
{
   questionFormat questions[20];

   srand(time(NULL));

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

   conductTests(questions, numQuestions);

   return 0;
}