Skip to main content

Arrays of Structs

In our earlier paralell arrays example, we wrote a function for sorting the paralell arrays:

void sortStudents(int studentNumber[], float midterms[], float finals, int used);
void sortStudents(int studentNumber[], float midterms[], float finals, int used)
{
int i; //index for outer loop
int j; //index for inner loop
int tmp; //used for swapping
float tmpFloat; //used for swapping floats
//repeat going through the array n-1 times
for (i=0; i<used-1; i++){
//go from start of array up to the end of the unsorted part
for(j=0; j<used-1-i; j++){
//if the adjacent values are not in order swap them. Note how you
//only check student number since we are ordering just by student
//numbers.. but if we have to swap, we swap elements in all 3 arrays
if(studentNumber[j] > studentNumber[j+1]){
//swap student numbers
tmp = studentNumber[j];
studentNumber[j] = studentNumber[j+1];
studentNumber[j+1] = tmp;

//swap midterms values
tmpFloat = midterms[j];
midterms[j] = midterms[j+1];
midterms[j+1] = tmpFloat;

//swap finals values
tmpFloat = finals[j];
finals[j] = finals[j+1];
finals[j+1] = tmpFloat;

}
}
}
}

This function required that all 3 arrays be passed to the function. Within the code, every swap required a corresponding swap in all 3 arrays. What would happen if we wanted to store more information than just midterm and final tests? Consider the number of grades you need to store for IPC144... you would need a lot more arrays to store all the grades. The bubble sort function above would also get a lot more complicated as it would require a swap on every array.

While parallel arrays do offer a method of organizing related data, they tend to be cumbersome once you have more than a couple of pieces of related information.

Arrays of Structs.

A superior method of storage is that of an array of structs. A struct stores multiple pieces of related information. For example, a struct can store all the grades for one student. An array of structs allow you to store the grades for multiple students.

To rewrite our solution for our paralell array example we would create a struct that will store our information for one student into a struct.

struct StudentScore
{
int studentNumber;
float midterm;
float final;
};

If we combine what we know, we can now create an array of these structs using the following declaration:


struct Student classMarks[40];

The single declaration above replaces the 3 parallel array declarations we had previously done.

Every element of this array holds all the score for a single student.

Initializing an array of structs

We can extend our initialization method for structs and arrays to initialize an array of structs.

To initialize an array we provide a comma separated listed where each thing item initializes a single element:

datatype array[CAP] = {element1, element2, element3, ...};

To initialize a struct we use a comma separated list for each data member based on the order that they are declared.

struct StructName mystruct = {datamember1, datamember2, datamember3,...};

Now we need to combine these together to initialize an array using the information below:

Student 1:

  • student number: 123456
  • midterm: 63.5
  • final: 65.0

Student 2:

  • student number: 654321
  • midterm: 70.5
  • final: 75.3

Student 3:

  • student number: 345678
  • midterm: 91.5
  • final: 82.3
struct StudentScore
{
int studentNumber;
float midterm;
float final;
};
...

struct StudentScore students[40]={
{123456, 63.5, 65.0},
{654321, 70.5, 75.3},
{345678, 91.5, 82.3}
};

Weighted Average function

The following is a rewrite of the weighted average function that uses an array of StudentScore structs instead of 3 parallel arrays. Note that when you pass arrays structs to functions, the array refers to the original and can be altered. If the function does not modify the array's content we should put a const keyword on the array so that any unintended modifications will get flagged by the compiler.

/* This function is passed a key (the student number we are searching for), and
an array of StudentScore structs. The function returns the weighted average of
midterm and finals (40% midterm, 60% final)*/
float weightedAverage(int key, const struct StudentScore students[], int used){
int idx = -1;
int i;
//look for idx, this loop stops when we find a matching number or we get to end of array
for(i = 0; i < used && idx == -1;i++){
if(key == students[i].studentNumber){
idx = i;
}
}

//we assumed the student number always exists so no error checking is done here
return students[idx].midterm * 0.4 + students[idx].final * 0.6;
}

Sorting array of Structs

Here is how we can sort an array of structs by the student number. This is a significant simplication to what we had to do for sorting 3 parallel arrays. Furthermore, if we were to add other information to our struct (storing all lab scores for example), this function would still work. We treat each instance of our struct as one single entity as opposed to each piece of data separately. This simplifies our code signficantly.

void sortStudents(struct StudentScore students[], int used)
{
int i; //index for outer loop
int j; //index for inner loop
struct StudentScore tmp; //used for swapping
//repeat going through the array n-1 times
for (i=0; i<used-1; i++){
//go from start of array up to the end of the unsorted part
for(j=0; j<used-1-i; j++){
//if the adjacent values are not in order swap them.
if(students[j].studentNumber > students[j+1].studentNumber){
//swap student. Note that the entire struct is swapped,
//not just the student number
tmp = students[j];
students[j] = students[j+1];
students[j+1] = tmp;
}
}
}
}