An array program won't compile

I'm attempting to do the following problem:


Write a program for the following problem. You’re given a file that contains a collection if IDs and scores (type int) for an exam in your computer course. You’re to compute the average of these scores and assign grades to each student according to the following rule:

If a student’s score is within 10 points (above or below) of the average, assign a grade of satisfactory. If a studnt’s score is more than 10 points above average, assign a grade of outstanding. If a student’s score is more than 10 points below average, assign a grade of unsatisfactory.

The output from your program should consist of a labeled three-column list that shows each ID, score, and corresponding grade. Use a struct to store each student’s data and an array of structs to store the whole class. The struct should have a data member for id, score, and grade.


The file given to us 'grades' is as follows:

3313 90 42 58 64 70 75 100
5688 88 48 79 70 79 70 94
4700 50 44 89 73 70 73 100
9561 88 69 88 87 84 63 98
3199 96 69 100 90 88 67 100
3768 78 57 80 59 57 15 60
8291 72 56 70 82 74 9 83
7754 76 62 93 100 78 41 58
8146 94 68 99 94 93 9 54
2106 98 47 96 94 70 27 100

So far, I have this 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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <fstream>		//required for file streams
#include <iostream>		//input/output
#include <cstdlib>		//for definition of EXIT_FAILURE
#include <string>
#include <iomanip>

using namespace std;

#define inFileGrades "grades.txt"	//grades
#define outFile "gradesOut.txt"	//grade sheet

//Functions used
void processGrades (ifstream&, ofstream&, int&, int&);		//process all 
void classAverage (double&, double&, string&);

int main()
{
	ifstream grades;		//input: grades
	ofstream gradesOut;		//output: all info per employee
	int studentSum;		//sum value
	int totalSum;			//totalSum
	studentSum = 0;			//initiate sum
	totalSum = 0;			//initiate total sum
	
	
	
	

	//Prepare files
	grades.open(inFileGrades);	//open grade file
	if (grades.fail())		//if file doesn't read in, fail message
	{
		cerr << "*** ERROR: Cannot open " << inFileGrades << " for input." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	gradesOut.open(outFile);			//make output file
	if (gradesOut.fail())			//if file isn't made, fail message
	{
		cerr << "*** ERROR: Cannot open " << gradesOut << " for output." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	processGrades(grades,		//process grade file to form output file
		gradesOut, 
		studentSum, 
		totalSum);	


	//Close files	
	grades.close();
	gradesOut.close();

	
	return 0;
}

void processGrades(ifstream& grades,
	 	ofstream& gradesOut,
		int& studentSum,
		int& totalSum)
		
{
	const int MAX_IDS = 10;
	const int MAX_SCORE = 7;	
	int id[MAX_IDS];		//student id
	int score[MAX_SCORE];		//first score
	double studentAverage[MAX_IDS];		//average value
	double totalAverage;
	string third[MAX_IDS];
	
	
	for (int j = 0;
		j < MAX_IDS;
		j++)
	{
		for (int i = 0;
			i < MAX_SCORE;
			i++)
		{
			grades >> id[j] >> score[i];
			studentSum += score[i];
			studentAverage[j] = studentSum / MAX_SCORE;
			totalSum = totalSum + studentSum;
		}
		studentSum = 0;
	}
	totalAverage = totalSum / MAX_IDS;
	
	classAverage (studentAverage, 
		totalAverage, 
		third);
	
	for (int j = 0;
		j < MAX_IDS;
		j++)
	{
	gradesOut << setw(4) << id[j] << setw(8) << studentAverage[j] << setw(14) << third[j];
	}

}

void classAverage (double& studentAverage, 
		double& totalAverage,
		string& third)
{
	if (studentAverage < totalAverage - 10)
		{
			third == "Unsatisfactory";
		}
	else if (studentAverage > totalAverage + 10)
		{
			third == "Oustanding";
		}
	else
		{
			third == "Satisfactory";
		}
}


I'm not sure how close I am, because it will not compile do to this error.
./grader.cpp: In function `void processGrades(std::ifstream&, std::ofstream&, int&, int&)':
./grader.cpp:97: error: invalid initialization of non-const reference of type 'double&' from a temporary of type 'double*'
./grader.cpp:19: error: in passing argument 1 of `void classAverage(double&, double&, std::string&)'

I appreciate any advice.
The problem is in function processGrades(). You have declarations:
1
2
3
	double studentAverage[MAX_IDS];		//average value
	double totalAverage;
	string third[MAX_IDS];
Then you do:
1
2
3
	classAverage (studentAverage, 
		totalAverage, 
		third);


void classAverage (double&, double&, string&); means that classAverage should be called with two doubles and a string. But you're trying to pass a double array, a double and a string array.

Given your requirement
You’re to compute the average of these scores and assign grades to each student
, I can't see where you read in all scores for an id and calculate the average for it.
Last edited on
I was hoping the student average would do that. How do I pass an array?
Nevermind, I was overthinking that part.

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115


#include <fstream>		//required for file streams
#include <iostream>		//input/output
#include <cstdlib>		//for definition of EXIT_FAILURE
#include <string>
#include <iomanip>

using namespace std;

#define inFileGrades "grades.txt"	//grades
#define outFile "gradesOut.txt"	//grade sheet

//Functions used
void processGrades (ifstream&, ofstream&, int&, int&);		//process all 


int main()
{
	ifstream grades;		//input: grades
	ofstream gradesOut;		//output: all info per employee
	int studentSum;		//sum value
	int totalSum;			//totalSum
	studentSum = 0;			//initiate sum
	totalSum = 0;			//initiate total sum
	
	
	
	

	//Prepare files
	grades.open(inFileGrades);	//open grade file
	if (grades.fail())		//if file doesn't read in, fail message
	{
		cerr << "*** ERROR: Cannot open " << inFileGrades << " for input." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	gradesOut.open(outFile);			//make output file
	if (gradesOut.fail())			//if file isn't made, fail message
	{
		cerr << "*** ERROR: Cannot open " << gradesOut << " for output." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	processGrades(grades,		//process grade file to form output file
		gradesOut, 
		studentSum, 
		totalSum);	


	//Close files	
	grades.close();
	gradesOut.close();

	
	return 0;
}

void processGrades(ifstream& grades,
	 	ofstream& gradesOut,
		int& studentSum,
		int& totalSum)
		
{
	const int MAX_IDS = 10;
	const int MAX_SCORE = 7;	
	int id[MAX_IDS];		//student id
	int score[MAX_SCORE];		//first score
	double studentAverage[MAX_IDS];		//average value
	double totalAverage;
	string third[MAX_IDS];
	
	
	for (int j = 0;
		j < MAX_IDS;
		j++)
	{
		for (int i = 0;
			i < MAX_SCORE;
			i++)
		{
			grades >> id[j] >> score[i];
			studentSum += score[i];
			studentAverage[j] = studentSum / MAX_SCORE;
			totalSum = totalSum + studentSum;
		}
		studentSum = 0;
	}
	totalAverage = totalSum / MAX_IDS;
	
	
	for (int j = 0;
		j < MAX_IDS;
		j++)
	{
		
		if (studentAverage[j] < totalAverage - 10)
		{
			third[j] == "Unsatisfactory";
		}
		else if (studentAverage[j] > totalAverage + 10)
		{
			third[j] == "Oustanding";
		}
		else
		{
			third[j] == "Satisfactory";
		}

	gradesOut << setw(4) << id[j] << setw(8) << studentAverage[j] << setw(14) << third[j] << "\n";
	}

}


Now I just have to get the logic right, arrays are still a bit confusing to me.
You're trying to read a line like this:
3313 90 42 58 64 70 75 100


So for each line, you need to read the id, the read seven scores. At the moment, you're reading id/score seven times, which isn't the same thing.

Let's try to fix reading the stuff in first before doing the rest.
Yes, I was trying to set up an array for the seven scores. I'm starting to think I just need to do one array per line, then when I sum, etc. do it from x1 on, and display x0 as the id later.
The data structures are fine, you don''t need to change those. The problem is with filling them with data from the file.

As you know there is one id and seven scores, so the read code looks like:
1
2
3
4
for line = 0; i < MAX_LINES; ++line
    read id[line]
    for i = 0; i < MAX_SCORES; ++i
        read score[line][i]


Once you understand that, you may consider making it cope with a variable number of lines and scores. But that's not essential right now. The main thing is to read the data from the file into your arrays.
I just realized I'm supposed to "Use a struct to store each student’s data and an array of structs to store the whole class. The struct should have a data member for id, score, and grade." My current setup doesn't accomplish this correct? I may have to go back to the drawing board...
Well, I think I'm getting closer in theory, but it's still not right.

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


//grader.cpp
//Grades
//Cory Morewitz
//7/2/2012

#include <fstream>		//required for file streams
#include <iostream>		//input/output
#include <cstdlib>		//for definition of EXIT_FAILURE
#include <string>
#include <iomanip>

using namespace std;

#define inFileGrades "grades.txt"	//grades
#define outFile "gradesOut.txt"	//grade sheet

//Functions used
void marks(ifstream&, ofstream&);

int main()
{
	ifstream grades;		//input: grades
	ofstream gradesOut;		//output: all info per employee
	
	//Prepare files
	grades.open(inFileGrades);	//open grade file
	if (grades.fail())		//if file doesn't read in, fail message
	{
		cerr << "*** ERROR: Cannot open " << inFileGrades << " for input." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	gradesOut.open(outFile);			//make output file
	if (gradesOut.fail())			//if file isn't made, fail message
	{
		cerr << "*** ERROR: Cannot open " << gradesOut << " for output." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	marks(grades,		//process grade file to form output file
		gradesOut);	


	//Close files	
	grades.close();
	gradesOut.close();

	
	return 0;
}

void marks (ifstream& grades,
		ofstream& gradesOut)
{
	const int MAX_IDS = 10;
	const int MAX_SCORE = 7;
	int sum;
	float totalAverage;
	struct examStats
	{
		int id[MAX_IDS];
		int scores[MAX_SCORE];
		float average;
		string success;
	};
	struct examStats aStudent;
		for (int j = 0;
			j < MAX_IDS;
			j++)
		{
			for (int i = 0;
				i < MAX_SCORE;
				i++)
			{
				grades >> aStudent.id[j] >> aStudent.scores[i];
				sum = 0;
				sum += aStudent.scores[i];
			}
			aStudent.average = 0;
			aStudent.average = (sum / MAX_SCORE);
			totalAverage = 0;
			totalAverage += aStudent.average;
		}
		totalAverage = (totalAverage / MAX_IDS);
		
		gradesOut << setw(4) << "ID" << setw(8) << "Student Average" << setw(14) << "Grade" << "\n";
		for (int j = 0;
			j < MAX_IDS;
			j++)
			gradesOut <<setw(4) << aStudent.id[j] << setw(8) << aStudent.average << setw(14) << totalAverage << "\n";
}
	


My output file is off though, it is as follows:


IDStudent Average Grade
70 13 1.3
69 13 1.3
3768 13 1.3
9 13 1.3
94 13 1.3
27 13 1.3
2664824 13 1.3
1628822316 13 1.3
1628995352 13 1.3
1629093531 13 1.3

A few points:
1. First some syntax. In C, when you declare a struct, you need to use the word struct wherever you use the name. For example:
 
struct stat fileinfo;

But in C++, you don't need to keep saying struct or class. There's a technical reason for this, but suffice to say, if you declare a struct examStats, you declare a variable of that type as:
 
examStats info;
no mention of struct.

2. Your have multiple scores and averages per person, so your struct should probably reflect that.
1
2
3
4
5
6
struct Person
{
    int id;  // person id from file
    int scores[MAX_SCORE];  // array of scores for this person
    float average;  // calculated average score for this person
};


3. Then you data on multiple persons, so you can represent that with an array.
 
Person[MAX_IDS] persons;


4. You're initialising sums in your loops, this means they keep getting reset. In C++, it's common practice to initialise variables on declaration. If you do that when you declare your variables, you eliminate this problem of wondering where to initialise them, and so end up not intitalising them in loops.
I see, if made some changes, though I'm not getting a compiler error:

./graderNew.cpp:86: error: no match for 'operator[]' in 'examstats[i]'

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
#include <fstream>		//required for file streams
#include <iostream>		//input/output
#include <cstdlib>		//for definition of EXIT_FAILURE
#include <string>
#include <iomanip>

using namespace std;

#define inFileGrades "grades.txt"	//grades
#define outFile "gradesOut.txt"	//grade sheet
const int MAX_IDS = 10;
const int MAX_SCORE = 7;
struct examStats
{
	int id;
	int scores[MAX_SCORE];
	float average;
	string success;
}examstats[MAX_IDS];

//Functions used
void marks(ifstream&, ofstream&);
void printexamStats (examStats examstats);

int main()
{
	ifstream grades;		//input: grades
	ofstream gradesOut;		//output: all info per employee
	
	//Prepare files
	grades.open(inFileGrades);	//open grade file
	if (grades.fail())		//if file doesn't read in, fail message
	{
		cerr << "*** ERROR: Cannot open " << inFileGrades << " for input." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	gradesOut.open(outFile);			//make output file
	if (gradesOut.fail())			//if file isn't made, fail message
	{
		cerr << "*** ERROR: Cannot open " << gradesOut << " for output." << "\n";
		return EXIT_FAILURE;	//failure return
	}
	
	marks(grades,		//process grade file to form output file
		gradesOut);	


	//Close files	
	grades.close();
	gradesOut.close();

	
	return 0;
}

void marks (ifstream& grades,
		ofstream& gradesOut)
{
	int sum = 0;
	float totalAverage;
	examStats examstats;
		for (int i = 0; i < MAX_IDS; i++)
		{
			grades >> examstats.id;
			for (int i = 0;
				i < MAX_SCORE;
				i++)
			{
				grades >> examstats.scores[i];
				sum += examstats.scores[i];
			}
			examstats.average = (sum / MAX_SCORE);
			totalAverage += examstats.average;
		}
		totalAverage = (totalAverage / MAX_IDS);
		
		cout << setw(4) << "ID" << setw(8) << "Student Average" << setw(14) << "Grade" << "\n";
		for (int i = 0; i < MAX_IDS; i++)
		{
			printexamStats (examstats[i]);
		}
}

void printexamStats (examStats examstats)
{
cout << setw(4) << examstats.id << setw(8) << examstats.average << setw(14) << "\n";
}
This is just a matter of style, but it's important. Never mix the declaration of a struct or class and the declaration of a variable of that type in the same statement. For example:
1
2
3
4
5
6
7
struct examStats
{
	int id;
	int scores[MAX_SCORE];
	float average;
	string success;
}examstats[MAX_IDS];


If that's what you really want, make the definition and declaration as seperate statements.
1
2
3
4
5
6
7
8
9
10
// define examStats
struct examStats
{
	int id;
	int scores[MAX_SCORE];
	float average;
	string success;
};

examStats examstats[MAX_IDS];  // declare examstats 

As it happens, you don't want that global examstats variable, so don't declare it. It's never used and technicallty incorrect as you really should try not to use global variables.

Having said that, your function is looking a lot better.
1. You have a local variable, examstats, which has all your data. But it ought to be an array of examStats, right? The variable you declared global should be moved here.

2. You have initialiased sum on declaration, that's good. But sum is used for each student, so it should be declared in the first loop.

3. totalAverage is still uninitialised. It's a hang over from C, but it you declare one of these built in types/plain old data types, you have to initialise them yourself.

4. When you read an id, you're reading the ith id, so it should go into an array. Similarly, you read the scores and calculate average and score on ith entry.

5. You have two nested loops, that process each student and scores for each student, that's good. But both loops use i as the index.
Last edited on
Topic archived. No new replies allowed.