Exam Grader

Hello, I can't figure out one thing about this program! I need your help, please:

One of your professors has asked you to write a program to grade her final exams, which consist of only 20 multiple-choice questions. Each question has one of four possible answers: A, B, C, or D. The file CorrectAnswers.txt contains the correct answers for all of the questions, with each answer written on a separate line. The first line contains the answer to the first question, the second line contains the answer to the second question, and so forth. Write a program that reads the contents of the CorrectAnswers.txt file into a char array, and then reads the contents of another file, containing a student’s answers, into a second char array.

The program should determine the number of questions that the student missed, and then display the following:

• A list of the questions missed by the student, showing the correct answer and the incorrect answer provided by the student for each missed question

• The total number of questions missed

• The percentage of questions answered correctly. This can be calculated as Correctly Answered Questions ÷ Total Number of Questions

• If the percentage of correctly answered questions is 70% or greater, the program should indicate that the student passed the exam. Otherwise, it should indicate that the student failed the exam.


I have this so far, but I don't know how to use the string thingy so that it shows me the line in the file so I can say which questions they missed

int main()
{
const int size = 300;
static int count = 0;
string correctAnswers[size];
string studentAnswers[size];
ifstream infileC;

infileC.open("CorrectAnswers.txt");

if (infileC)
{
for (int i = 0; i<20; i++)
{
infileC >> correctAnswers[i];
}
}
else
{
cout << "File open failure!" << endl;
}

infileC.close();

ifstream infileS;
infileS.open("StudentAnswers.txt");

if (infileS)
{
for (int t = 0; t<20; t++)
{
infileS >> studentAnswers[t];
}
}
else
{
cout << "File open failure!" << endl;
}
infileS.close();

cout << "Report for Student 1: " << endl;
for (int x = 0; x<20; x++)
{

if (correctAnswers[x] != studentAnswers[x])
{
count++;
}
}
int percent = ((double)(20 - count) / 20) * 100;
cout << endl << "Missed " << count << " out of 20 questions for " << percent << "% correct." << endl;

cout << "Questions missed: " << endl;
for (int x = 0; x<20; x++)
{

if (correctAnswers[x] != studentAnswers[x])
{
string to_string(<number>);

cout << "(" << studentAnswers[x] << "/" << correctAnswers[x] << "), ";

}
}

if (percent >= 70)
{
cout << endl << "This student passed the exam!" << endl;
}
else
{
cout << endl << "This student failed the exam." << endl;
}
return 0;
}
show us what CorrectAnswers.txt looks like
CorrectAnswers.txt looks like this:
It has lines though next to them indicating where they are, I just don't know how to put that here
A
D
B
C
A
A
D
B
D
C
A
D
B
A
C
C
D
B
C
A
StudentAnswers.txt has 220 lines but I am only checking the first 20 lines, which counts as one student's exam, so:
A
D
B
C
B
A
C
B
D
C
A
D
B
A
C
A
D
B
C
A
And I want to say that some of the questions/lines were missed as you can see by the correctanswers.txt
Last edited on
OP: I have good news and bad news for you. On the positive side I can offer you a Student struct with various data members corresponding to your requirements and, additionally, the student name which I think is important, an overloaded << operator for printing and a tried and tested method of extracting the data from file and saving it in standard containers. The bad news is that what I thought would be the easy part, checking the answers, doesn't seem to work. I'm just not being able to reach inside the vector where the student answers are stored and tick them off against the correct answers. I'm posting what I have so far in the hope that some kind soul may be able to help both of us out of our respective miseries.

Correct answers file: http://pastie.org/10981011
Two students answers' file: http://pastie.org/10981012

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

using namespace std;

struct Student
{
    string m_name;
    vector<pair<string,string>> m_checked_answers;
    int m_q_missed = 0;
    int m_q_correct = 0;
    string m_pass_fail = "Pass";
};
ostream& operator << (ostream& os, const Student& s)
{
    os << "Student: " << s.m_name << '\n';
    for (auto& elem : s.m_checked_answers)
    {
        os << elem.first << elem.second << '\n';
    }
    os << "Missed questions: " << s.m_q_missed << '\n';
    os << "Correct answers: " << s.m_q_correct << '\n';
    os << "Final result: " << s.m_pass_fail << '\n';
    return os;
}

int main()
{
    ifstream infile_correct_answers("C:\\test1.txt");
    string str;
    vector<string> correct_answers;
    while (infile_correct_answers >> str)
    {
        correct_answers.push_back(move(str));
    }
    cout << "Correct answers: \n";
    for (auto& elem : correct_answers)
    {
        cout << elem << " ";
    }
    cout << '\n';
    ifstream infile_student_answers("C:\\test.txt");
    vector<Student> students;
    while(infile_student_answers)
    {
        string name;
        getline(infile_student_answers, name);
        Student s;
        s.m_name = name;
        int i = 0;
        string answer;
        do
        {
            getline(infile_student_answers, answer);
            s.m_checked_answers.push_back(make_pair(answer, " ** "));
            i++;
        }   while (i < 20);
        if(infile_student_answers)
        {
            students.push_back(s);
        }
    }
    Student s;
    for (size_t i = 0; i < students.size(); i++)
    {
        for (size_t j = 0; j < s.m_checked_answers.size(); j++ )
        {
            if(students[i].m_checked_answers[j].first == correct_answers[j])//NOT WORKING!!!
            {
                students[i].m_q_correct++;
            }
            else
            {
                students[i].m_checked_answers[j].second = string ("Correct answer is: ") + correct_answers[j];
                students[i].m_q_missed++;
            }
        }
        if(students[i].m_q_correct < 0.7 * (students[i].m_checked_answers.size()))
        {
            students[i].m_pass_fail = "Fail";
        }
    }
    for (auto& elem : students)
    {
       cout << elem ;
    }
}

Yes I did. Can you help with the bit where we're stuck?
Last edited on
OP: I'm glad to report that the quirks in the program have been removed. Turned out that the correct_answers vector needed its own iterator to reach inside it, trying

to read it off an index linked to the struct's vector member was not working.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

using namespace std;

struct Student
{
    string m_name;
    vector<pair<string,string>> m_checked_answers;
    int m_q_missed = 0;
    int m_q_correct = 0;
    string m_pass_fail = "Pass";
};
ostream& operator << (ostream& os, const Student& s)
{
    os << "Student: " << s.m_name << '\n';
    for (auto& elem : s.m_checked_answers)
    {
        os << elem.first << elem.second << '\n';
    }
    os << "Missed questions: " << s.m_q_missed << '\n';
    os << "Correct answers: " << s.m_q_correct << '\n';
    os << "Final result: " << s.m_pass_fail << '\n';
    return os;
}

int main()
{
    ifstream infile_correct_answers("C:\\test1.txt");
    string str;
    vector<string> correct_answers;
    while (infile_correct_answers >> str)
    {
        correct_answers.push_back(move(str));
    }
    cout << "Correct answers: \n";
    for (auto& elem : correct_answers)
    {
        cout << elem << " ";
    }
    cout << '\n';
    ifstream infile_student_answers("C:\\test.txt");
    vector<Student> students;
    while(infile_student_answers)
    {
        string name;
        getline(infile_student_answers, name);
        Student s;
        s.m_name = name;
        int i = 0;
        string answer;
        do
        {
            getline(infile_student_answers, answer);
            s.m_checked_answers.push_back(make_pair(answer, " ** "));
            i++;
        }   while (i < 20);
        if(infile_student_answers)
        {
            students.push_back(s);
        }
    }
    Student s;
    for (size_t i = 0; i < students.size(); i++)
    {
        vector<pair<string, string>>::iterator itr_stu = students[i].m_checked_answers.begin();
        vector<string>::iterator itr_ans = correct_answers.begin();
        do
        {
            if((*(itr_stu)).first == *(itr_ans))
            {
                students[i].m_q_correct++;
                itr_stu++;
                itr_ans++;
            }
            else
            {
                (*(itr_stu)).second = string(" Correct answer is: ") + *(itr_ans);
                students[i].m_q_missed++;
                itr_stu++;
                itr_ans++;
            }

        }while((itr_stu != students[i].m_checked_answers.end())&& itr_ans != correct_answers.end());


        if(students[i].m_q_correct < 0.7 * (students[i].m_checked_answers.size()))
        {
            students[i].m_pass_fail = "Fail";
        }
    }
     for (auto& elem : students)
    {
       cout << elem ;
    }
}

It is very clumsy with multiple students, I'm afraid.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;

int main()
{
   const int size = 300;
   const int EXAMSIZE = 20;                      // <===== Number of questions
   int count;
   char correctAnswers[EXAMSIZE];                // <===== Your teacher asked for character arrays
   char studentAnswers[EXAMSIZE];
   int studentNumber = 0;


   // Read correct answers
   ifstream infileC( "CorrectAnswers.txt" );     // <===== Open with constructor
   if ( !infileC )
   {
      cout << "Error opening correct answers file" << endl;
      return 1;                                  // <===== Stop at failure
   }
   for ( int i = 0; i < EXAMSIZE; i++ )       
   {
      infileC >> correctAnswers[i];
      infileC.ignore( 256, '\n' );               // <===== Make sure to get beyond the linefeed
   }
   infileC.close();


   ifstream infileS( "StudentAnswers.txt" );     // <===== Open with constructor
   if ( !infileS )
   {
      cout << "Error opening student answers file" << endl;
      return 1;                                  // <===== Stop at failure
   }


   // Student by student
   while ( infileS )                             // <===== Comment out this line for only one student
   {
      studentNumber++;                           // <===== Next student

      // Read answers
      for ( int i = 0; i < EXAMSIZE; i++ )  
      {
         infileS >> studentAnswers[i];
         if ( !infileS ) return 0;               // <===== Need opportunity to escape if no more students (don't we all!)
         infileS.ignore( 256, '\n' );
      }

      // Produce report
      cout << "Report for Student " << studentNumber << ": "  << endl;
      cout << "The student got the following answers wrong: " << endl;
      count = 0;
      for ( int i = 0; i < EXAMSIZE; i++)
      {
         if ( correctAnswers[i] != studentAnswers[i] )
         {
            count++;
            cout << "Question number: " << setw( 2 ) << i + 1
                 << "   Student answer: " << studentAnswers[i]
                 << "   Correct answer: " << correctAnswers[i] << endl;
         }
      }
      cout << endl;

      double percent = 100.0 * ( EXAMSIZE - count ) / EXAMSIZE;     // <===== 100.0 first prevents integer division error
      cout << "Number of questions wrong: " << count   << endl;
      cout << "Percentage correct:        " << percent << endl;
      cout << endl;

      if ( percent >= 70.0 ) cout << "This student passed the exam" << endl;
      else                   cout << "This student failed the exam" << endl;

      cout << endl << endl;
   }                                                                // <=====Comment out this line for only one student

   infileS.close();
} 



studentAnswers.txt:
A
D
B
C
B
A
C
B
D
C
A
D
B
A
C
A
D
B
C
A
A
D
D
C
B
A
C
B
D
A
A
D
B
A
C
B
C
B
E
A



Output:
Report for Student 1: 
The student got the following answers wrong: 
Question number:  5   Student answer: B   Correct answer: A
Question number:  7   Student answer: C   Correct answer: D
Question number: 16   Student answer: A   Correct answer: C

Number of questions wrong: 3
Percentage correct:        85

This student passed the exam


Report for Student 2: 
The student got the following answers wrong: 
Question number:  3   Student answer: D   Correct answer: B
Question number:  5   Student answer: B   Correct answer: A
Question number:  7   Student answer: C   Correct answer: D
Question number: 10   Student answer: A   Correct answer: C
Question number: 16   Student answer: B   Correct answer: C
Question number: 17   Student answer: C   Correct answer: D
Question number: 19   Student answer: E   Correct answer: C

Number of questions wrong: 7
Percentage correct:        65

This student failed the exam
Topic archived. No new replies allowed.