I'll have to look into this more on the weekend have another problem I have to finish sadly
Perhaps it might help to look at it a different way.
Assume you have STUDENTS students, COURSES courses, and PARTS parts to each course, with each part graded:
The order of the dimensions determines what you can overall refer to.Code:#define STUDENTS 20 #define COURSES 5 #define PARTS 3
For example, if you define
then grade[student] is a two-dimensional array, double[COURSES][PARTS], specifying the grades for one student over all courses and parts, and grade[student][course] is an one-dimensional array, double[PARTS], specifying the grades for each part for one student on one course.Code:double grade[STUDENTS][COURSES][PARTS];
If, however, you define
then grade[course] is a two-dimensional array, double[PARTS][STUDENTS], specifying the grades for all students and all parts of that course, and grade[course][part] is an one-dimensional array, double[STUDENTS], specifying the grades for a specific course and part for all students.Code:double grade[COURSES][PARTS][STUDENTS];
So, the way you define your array indices, define the ways you can use your arrays in C.
For general-purpose one-, two-, or three-dimensional arrays, I would use
The functions to handle this are straightforward, but require detailed knowledge about structures and pointers.Code:struct data { struct data *next; long refcount; size_t size; double data[]; }; struct array3d { long step[3]; long size[3]; double *origin; struct data *owner; }; struct array2d { long step[2]; long size[2]; double *origin; struct data *owner; }; struct array1d { long step; long size; double *origin; struct data *owner; }; #define ELEMENT3D(array, x, y, z) \ ((array)->origin[(x)*(array)->step[0] + (y)*(array)->step[1] + (z)*(array)->step[2]]) #define ELEMENT2D(array, x, y) \ ((array)->origin[(x)*(array)->step[0] + (y)*(array)->step[1]]) #define ELEMENT1D(array, x) \ ((array)->origin[(x)*(array)->step])
The point of the structures is that actual data is stored in the first structure, and the others just reference the data. (Counting the number of references to each instance of the first structure allows the program/library to free the data when it is no longer needed, as long as the programmer remembers to free each array when no longer needed.)
(I use long for the size and step fields, because int is not large enough on 64-bit architectures.)
Given a 3D array, a 2D array can be any regular plane within the array. (Regular in the sense that the coordinates for the elements must be specified with a linear integer equation.)
Given a 3D or 2D array, an 1D array can be any regular line within the array. (Again, regular in the sense that the coordinates for the elements must be specified with an linear integer equation.)
In other words, you can mirror, flip, and/or pick every N'th element from another array (having equal or greater number of dimensions).
(It is also possible to expand certain 1D arrays to 2D and 3D, and 2D arrays to 3D, if the same data is repeated. For example, you can create a 3D array with any number of elements, with all the elements always having the exact same value, since they all share the same data.)
There is a very small additional cost to every element access, because all coordinates are multiplied to get the actual address, but it should be neglible in practice. In fact, Fortran does something very, very similar internally, to support arrays and array slicing.
Once again, the voice of reason: Nominal animal. Can you give a feash prospect to this conundrum?
I'm not sure if asking me is a good idea, Click_here. I seem to have a knack of raising hackles, even if I'm sincirely just trying to help.
Let's start at the beginning, the assignment:
First, define the constants and the grade array.Printing an average of all grades
Finding average grade for each subject for each student
Finding the average grade for each student in both subjects
2 subjects, 3 students, 4 exams
The grade per student per subject is then average(grade[student][subject]), where the parameter is of type double[EXAMS].Code:#define STUDENTS 3 #define SUBJECTS 2 #define EXAMS 4 double grade[STUDENTS][SUBJECTS][EXAMS];
The grade per student is then average(grade[student]), where the parameter is of type double[SUBJECTS][EXAMS].
The average grade is average(grade).
However, you need to output the intermediate averages too.
So, declare separate arrays for the averages, and an averaging function that takes an one-dimensional array as a parameter:
(I'm sure most of the readers have now realized my point.)Code:double subject_grades[STUDENTS][SUBJECTS]; double student_grades[STUDENTS]; double average_grade; double average(const double value[], const size_t values[]);
To populate the subject_grades array, you do a double loop, and calculate the average over the exams in that subject for that student.
Instead of calculating the student grades (student_grades array) from the grades array, you can calculate the averages of averages, i.e. averaging the subject_grades.
Finally, instead of calculating an average over the entire array to get the average grade overall, you average over the student_grades array.
I'll do the unthinkable and show the actual solution, because it really is this trivial:
If you wanted the average grade over all students for each subject, you cannot use the same function: you just cannot slice the existing arrays that way. This is the point I was trying to make earlier: the order of indices determines how you can slice the array.Code:int student, subject; for (student = 0; student < STUDENTS; student++) { /* Average grade per subject for this student: */ for (subject = 0; subject < SUBJECTS; subject++) subject_grades[student][subject] = average(grades[student][subject], EXAMS); /* Average grade for this student overall: */ student_grades[student] = average(subject_grades[student], SUBJECTS); } /* Average grade over all students (and subjects): */ average_grade = average(student_grades, STUDENTS);
Of course, calculating the average grade of all students per subject would be easy to do using two for loops:
If you look at the indexing, you'll realize that the inner loop accesses nonconsecutive members in the subject_gradesarray. Again, that means you cannot "slice" them to a function, the way we did earlier for the other arrays.Code:double average_subject[SUBJECTS]; for (subject = 0; subject < SUBJECTS; subject++) { average_subject[subject] = 0.0; for (student = 0; student < STUDENTS; student++) average_subject[subject] += subject_grades[student][subject]; average_subject[subject] /= (double)STUDENTS; }
I sincirely hope this clears the question. If not, please be gentle with your rebukes.