Need assistance finishing homework, almost done!

The homework problem I am working on ask me to grade a multiple choice exam. There are 20 multiple choice problems, with possible answers ranging from a to f. It wants me to read this text file:

abcdefabcdefabcdefab
1234567 abcdefabcdefabcdefab
9876543 abddefbbbdefcbcdefac
5554446 abcdefabcdefabcdef
4445556 abcdefabcdefabcdefabcd
3332221 abcdefghijklmnopqrst

where the first line is the answer key, on the second and following lines the first part (1234567) is the student number, and the second is their answers.

The book says the program should output:

1234567 20
9876543 15
5554446 Too Few Answers
4445556 Too Many Answers
3332221 Invalid Answers

When I compile and run my code it doesn't output anything, and looking over it I can't figure out where I went wrong.

Any help with this would be amazing, thank you in advance!

Here is my code:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void gradeTest (ifstream& inFile, ofstream& outFile)
{
int i = 1, j = 0, score = 0;
int key, ans;
string ansKey, answers, studentID;
string error1 = "Too Few Answers";
string error2 = "Too Many Answers";
string error3 = "Invalid Answers";

while (inFile)
{
if (i = 1)
{
inFile >> ansKey;
key = ansKey.length();
i = 2;
}
else
{
inFile >> studentID >> answers;
ans = answers.length();
if (key > ans)
outFile << studentID << " " << error1 << endl;
else if (key < ans)
outFile << studentID << " " << error2 << endl;
else if (key == ans)
{
while (ans > j)
{
if (answers[j] != 'a' && answers[j] != 'b' && answers[j] != 'c' && answers[j] != 'd' && answers[j] != 'e' && answers[j] != 'f')
{
outFile << error3 << endl;
j++;
break;
}
else
{
if (ansKey[j] == answers[j])
{
score = score + 1;
j ++;
}
else j ++;
}
outFile << studentID << " " << score << endl;
}
}
}
}

}

int main()
{
ifstream inFile;
ofstream outFile;

inFile.open("exams.dat");
outFile.open("scores.dat");

gradeTest(inFile,outFile);

return 0;
}
Last edited on
Edit your post to include code tags. It makes the whole thing so much more readable.

Looking at what's there, I see lots of brackets and I'm not sure what belongs to what.

Specific Issues:
 
if (i = 1)


Should be == rather than =. One is a true/false check, the other is assignment.

Is answers defined somewhere? I'm not seeing the array (and it'd be cleaner/safer as a vector, or even possibly a map in this case).

Also I'm not sure (due to the bracket issue) but your if/else chain might be causing problems. Have you considered using a switch statement instead?

It'd look something like this:
1
2
3
4
5
6
7
8
9
switch(somechar) {
case 'a': dosomething;
break;
case 'b': dosomething;
break;
//...
default: dosomethingelse;
break;
}


Finally, do you know where your files are going to show up? You might just be checking the wrong place -- the project folder is the likeliest bet!

General tips that I've read and thought were smart:
If you're using variables like error1, error2 etc, use a vector instead. It's neater, and it lets you do exactly the same thing.
score = score + 1 can be rewritten to score +=1, or just ++score. In other words, don't write more than you have to -- typing errors can cause lots of stupid problems.

Last edited on
1
2
3
4
5
6
7
8
while (inFile)
{
if (i = 1) // if(i==1)---you keep setting i to 1 skipping the rest of the code
{
inFile >> ansKey;
key = ansKey.length();
i = 2;
}
I made a few changes (thanks guys) but the output is still wrong.

The input is:

abcdefabcdefabcdefab
1234567 abcdefabcdefabcdefab
9876543 abddefbbbdefcbcdefac
5554446 abcdefabcdefabcdef
4445556 abcdefabcdefabcdefabcd
3332221 abcdefghijklmnopqrst

but the output is:

1234567 20
9876543 15
5554446 Too Few Answers
4445556 Too Many Answers
3332221 Invalid Answers
3332221 6
3332221 Invalid Answers
3332221 6

When it should be:

1234567 20
9876543 15
5554446 Too Few Answers
4445556 Too Many Answers
3332221 Invalid Answers

Which, to me, is saying that the break statement isn't doing anything.

This is the updated code:

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

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void gradeTest (ifstream& inFile, ofstream& outFile)
{
int i = 1;
int key, ans;
string ansKey, answers, studentID;
string error1 = "Too Few Answers";
string error2 = "Too Many Answers";
string error3 = "Invalid Answers";

while (inFile)
{
if (!inFile) break;
if (i == 1)
	{
	inFile >> ansKey;
	key = ansKey.length();
	i = 2;
	}
else
	{
	inFile >> studentID >> answers;
	ans = answers.length();
	     if (key > ans)
		outFile << studentID << " " << error1 << endl;
	else if (key < ans)
		outFile << studentID << " " << error2 << endl;
	else if (key == ans)
		{
		int j = 0;
		int score = 0;
		while (ans > j)
			{
			if (answers[j] != 'a' && answers[j] != 'b' && answers[j] != 'c' && answers[j] != 'd' && answers[j] != 'e' && answers[j] != 'f')
				{
				outFile << studentID << " " << error3 << endl;
				j = ans;
				break;
				}
			else
				{
				if (ansKey[j] == answers[j])
					{
					score = score + 1;
					j ++;
					}
				else j ++;
				}
			}
		outFile << studentID << " " << score << endl;
		}
	}
}

}

int main()
{
ifstream inFile;
ofstream outFile;

inFile.open("exams.dat");
outFile.open("scores.dat");

gradeTest(inFile,outFile);

return 0;
}

The problem is that answer.size() = 7, while you've only got 5 strings. So you're basically doing the same thing 8 times when you want to do it 5. Which is why you have surplus output.

One solution is a magic number, which will break things if you need to add more strings later.

The other option is making a vector<string> somename for your input, putting the input there, and then looping for i<somename.size() through the vector. This is the more robust solution.

I'd write it something like this:

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


for (int i=0; i<somename.size(); i++) { //counts the number of strings
		if (somename.at(i).size() > expected_size) //too big check
			error message;
		else if (somename.at(i).size() < expected_size) // too small check
			error message;
		else {
			for (int j=0; j<somename.at(i).size(); j++) {// counts the number of answers in a given string
		
				char answer = somename.at(i).string(j);
				switch (answer): {
					case 'a': 
						dosomething;
						break;
					case 'b': 
						dosomething;
						break;
						//...
					default:
						dosomethingwithwronganswer;
						break;
				
			}
		}
	}
}


That should pretty much handle anything that gets thrown at it.
Last edited on
But answer.length() should change with every pass through, shouldn't it?
For each individual string, yes. For the number of strings you are checking, no.

You've got two entities:
a group of strings
a group of answers inside the string

You need to count them separately. Otherwise you'll end up repeating the last string until you've reached the amount of input in that individual string, or not going through all those strings.

edit: Ha, I rewrote my code suggestion a couple of times. Turns out this is a fun little problem! I feel like I've gotten it down, but I still want there to be a way to avoid nested for-loops. Possibly by running the whole thing on answer straight as it comes in through a function call? Possibly! Tokenize input and check immediately, skipping all the for-loops? Would mean needless effort with wrong size strings though, but brute force on such a small set would be viable. I dunno, I guess it's not worth the effort to really over-engineer the solution. Nested for-loops are a quick and dirty solution.
Last edited on
The point of answer.length() is not for the number of strings I'm checking. while(inFile) is used for the number of strings that I'm checking, answer.length() is simply the number of characters in the students answers.
I changed it to
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
/*
* George Olson 0202411
* Chapter 8 Problem 7
*/

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void gradeTest (ifstream& inFile, ofstream& outFile)
{
int i = 1;
int key, ans;
string ansKey, answers, studentID;
string error1 = "Too Few Answers";
string error2 = "Too Many Answers";
string error3 = "Invalid Answers";

while (inFile)
{
if (!inFile) break;
if (i == 1)
	{
	inFile >> ansKey;
	key = ansKey.length();
	i = 2;
	}
else
	{
	//inFile >> studentID >> answers;
	ans = answers.length();
	     if (key > ans)
		outFile << studentID << " " << error1 << endl;
	else if (key < ans)
		outFile << studentID << " " << error2 << endl;
	else if (key == ans)
		{
		int j = 0;
		int score = 0;
		bool error3happened = false;
		while (ans > j)
			{
			if (answers[j] != 'a' && answers[j] != 'b' && answers[j] != 'c' && answers[j] != 'd' && answers[j] != 'e' && answers[j] != 'f')
				{
				outFile << studentID << " " << error3 << endl;
				bool error3happened = true;
				j = ans;
				//break;
				}
			else
				{
				if (ansKey[j] == answers[j])
					{
					score = score + 1;
					j ++;
					}
				else j ++;
				}
			}
		if (!error3happened)
		outFile << studentID << " " << score << endl;
		}
	}
inFile >> studentID >> answers;
}

}

int main()
{
ifstream inFile;
ofstream outFile;

inFile.open("exams.dat");
outFile.open("scores.dat");

gradeTest(inFile,outFile);

return 0;
}


And now my output is:

1234567 20
9876543 15
5554446 Too Few Answers
4445556 Too Many Answers
3332221 Invalid Answers
3332221 6

Which still has an extra "3332221 6" in it.
1
2
3
4
5
6
1234567 20             	                abcdefabcdefabcdefab 
9876543 15			1234567 abcdefabcdefabcdefab
5554446 Too Few Answers		9876543 abddefbbbdefcbcdefac
4445556 Too Many Answers        5554446 abcdefabcdefabcdef
3332221 Invalid Answers         4445556 abcdefabcdefabcdefabcd
3332221 6                       3332221 abcdefghijklmnopqrst


You have six letter chains in your declared input up top. There are only five number chains. Your code does not check that a number chain exists for a given input. This is likely the problem.
Last edited on
Topic archived. No new replies allowed.