Reputation: 3
Say I have the following code for taking the average of the class' math and science grade.
typedef struct
{
char name[30];
float math;
float science;
}
grade;
int n = 5;
grade grades[n];
float math_average(int n)
{
float run_sum = 0;
for (int i = 0; i < n; i++)
{
run_sum += grades[i].math;
}
return (run_sum / n);
}
float science_average(int n)
{
float run_sum = 0;
for (int i = 0; i < n; i++)
{
run_sum += grades[i].science;
}
return (run_sum / n);
}
Is it possible to create a generalized average function to have the same effect? So instead of n of subjects functions, I only have 1. Something like passing the subject as a parameter perhaps? Included example to better visualize of what I want to achieve:
float average(int n, /* [SUBJECT] */)
{
float run_sum = 0;
for (int i = 0; i < n; i++)
{
run_sum += grades[i]./*SUBJECT*/;
}
return (run_sum / n);
}
Upvotes: 0
Views: 68
Reputation: 120239
In general, if you have N
variables (fields) of the same nature, you don't have N
declarations, you declare an array of N
elements. Hence
#define MATH 0
#define SCIENCE 1
#define NUM_SUBJECTS 2
typedef struct
{
char name[30];
float subjects[NUM_SUBJECTS];
} grade;
Instead of writing grades[i].math
you write grades[i].subjects[MATH]
. And of course now you can write a general average routine by referring to grades[i].subjects[j]
.
Now if you would've thought that this sequence of #define
s at the beginning is dangerously stupid, you'd be right. I've only put them there for illustration. In reality, you use a single enum
declaration instead:
enum subjects { MATH, SCIENCE, NUM_SUBJECTS };
You just need to keep NUM_SUBJECTS
the last item in the list when you extend your list of subjects.
This approach naturally extends to the case when your list of subjects is not set in stone, but instead is one of the inputs of your program. You will need a dynamic array in one guise or another, for instance
typedef struct
{
char name[30];
int num_subjects;
float *subjects;
} grade;
but the generic average function code will remain unchanged.
Upvotes: 4
Reputation: 768
If you want, you can use offsetof
.
float average(int n, int offset)
{
float run_sum = 0;
for (int i = 0; i < n; i++)
{
//it's a little ugly, but should work as long as your average fields are float
run_sum += *(float*)(((byte*)&grades[i]) + offset);
}
return (run_sum / n);
}
math_average => average(n, offsetof(grade, math))
and so on...
Upvotes: 0