#include <stdio.h>
#include <stdlib.h>
/* Represents a students test */
struct t_exam {
int studentId; // the stuendent's unique id
char* answers; // responses to questions
int* correct; // questions that were right
int* incorrect; // questions that were wrong;
int grade; // (correct / questions) * 100
int totalCorrect; // total questions correct
int totalIncorrect; // total questions wrong
};
/* Represents the answers to an exam */
struct t_exam_key {
int questions; // number of questins on exam
char* answers; // the answers for the exam
};
/**
* int fscanf_key(FILE* fp, struct t_exam_key* key):
* fscans the number of questions and their answers from
* FILE at fp and stores in key.
* returns 1 if success, returns 0 if failure
*/
int fscan_key(FILE* fp, struct t_exam_key* key);
/**
* int fscan_exam(FILE* fp, struct t_exam* exam, int questions):
* fscans an exam entry from FILE at fp with arg3 questions.
* returns 1 if success, returns 0 if failure
*/
int fscan_exam(FILE* fp, struct t_exam* exam, int questions);
/**
* int grade_exam(struct t_exam* exam, struct t_exam_key* key):
* grades exam arg1 using exam_key arg2 as answer key
* returns 1 if success, returns 0 if failure
*/
void grade_exam(struct t_exam* exam, struct t_exam_key* key);
/**
* char fpeek(FILE fp):
* returns the next character to be read, but restores stream
*/
char fpeek(FILE* fp);
/**
* void free_exams(struct t_exam* exams, int number);
* Iterates through an array of exams, freeing allocated memory
* therein and finally freeing the first element of the array.
*/
void free_exams(struct t_exam* exams, int number);
int main(int argc, char **argv) {
FILE* examfp = fopen("examdat.txt", "r"); // the exam data
struct t_exam_key key; // the grading key for the exam
struct t_exam* exams = malloc(sizeof(struct t_exam)); // start to make room
int totalExams; // the total of exams completed
fscan_key(examfp, &key); // Read the key from the data file
/* load the exams in the file into the array and then grade*/
for(totalExams = 0; !feof(examfp) && fpeek(examfp) != '\n'; totalExams++) {
exams = realloc(exams, sizeof(struct t_exam) * totalExams + 1); // Reasize the array
fscan_exam(examfp, &exams[totalExams - 1], key.questions); // make
grade_exam(&exams[totalExams - 1], &key);
}
free_exams(exams, totalExams);
fclose(examfp);
return 0;
}
int fscan_key(FILE* fp, struct t_exam_key* key) {
if(!fscanf(fp, "%d", &key->questions)) { // scan the # of questions
return 0; // fail if they aren't there
}
key->answers = malloc(key->questions); // make space for answers
if (!fscanf(fp, " %s\n", key->answers)) { // store the answers
return 0; // fail if you can't
}
return 1; // success!
}
void grade_exam(struct t_exam* exam, struct t_exam_key* key) {
exam->totalCorrect = 0;
exam->totalIncorrect= 0;
exam->incorrect = malloc(sizeof(int) * key->questions);
exam->correct = malloc(sizeof(int) * key->questions);
int i;
for (i = 0; i < key->questions; i++) {
if (exam->answers[i] == key->answers[i]) {
exam->totalCorrect++;
exam->correct[i] = i;
} else {
exam->totalIncorrect++;
exam->incorrect[i] = i;
}
}
exam->grade = (exam->totalCorrect / ((float) key->questions)) * 100;
}
int fscan_exam(FILE* fp, struct t_exam* exam, int questions) {
exam->answers = malloc(questions);
if (!fscanf(fp, "%d %s\n", &exam->studentId, exam->answers)) {
free((void*)&exam->answers); // not needed anymore
return 0;
}
return 1;
}
void free_exams(struct t_exam* exams, int number) {
int i;
for(i = 0; i < number; i++) {
free((void*) exams[i].answers);
free((void*) exams[i].correct);
free((void*) exams[i].incorrect);
}
free((void*) &exams);
}
char fpeek(FILE* fp) {
char c = fgetc(fp);
ungetc(c, fp);
return c;
}