Saturday, January 20, 2018

Struct / Record




I'll motivate the concept of struct or record through an example, and I will explain the need for it from a software design perspective. Struct, as available in C++, will be a pre-cursor to the point I'm trying to get at - Object-Oriented Programming.

Now, suppose we have 3 list, as shown below:


One list holds the IDs for all students, another one holds the names, and the third one the grade for a particular subject. In C++, it would look like as follows, assuming an array representation for each of the list, and with a maximum array size of 100:

string id[100];
string name[100];
string grade[100];

We would read input as follows:
for (int i=0; i<100; i++)
       cin >> id[i] >> name[i] >> grade[i];


Though it may not seem to be so much of a problem, from a design perspective, it is problematic. We have data that are related together being stored in different lists. Imagine looking through a long list to search for an ID, and then looking through another list to know the person's name, and through yet another list to get the grade. It's cumbersome and error-prone, both in real life and in code (though it may not look that obvious in this tiny-mini code). We don't want this - data that belongs together should be together. So here comes
  struct
With struct, we can have things organized as follows:


Therefore, instead of a list of ID, a list of names and a list of grades, we have a list of records where each stores an ID, a name and a grade.  In C++, we would declare each of those records or structs as follows:

struct Student {
    string ID;
    string name;
    string grade;
    };

Student then becomes a new data type, and we can declare variables of type Student, as follows:

Student ali;

We access the different variables or fields inside Student via the dot notation, as shown below:

ali.ID = '12353';
ali.name = 'Ali';
ali.grade = 'A';

and we can declare an array of 100 records, as shown below:

Student students[100];

You can read input into the array, using the usual for loop, such as shown below:

for (int i=0; i<100; i++)  {
     cin >> students[i].ID;
     cin >> students[i].name;
     cin >> students[i].grade;
    }

You can do a million other things on it of course. 
     

Putting Functions in Struct


The cool thing about C++ compiler (such as g++) is that, unlike C (using gcc), it allows function in a struct. Now consider the following code:

Student students[100];

void welcomeScreen() { 
   cout << "Welcome to Registration App" << endl;
  }

int displayMenu() {
     cout << "Choices: 1) input 2) output" << endl;
     int choice;
     cin >> choice;
     return choice;
}

void input() {
     for (int i=0; i<100; i++)  {
         cin >> students[i].ID;
         cin >> students[i].name;
         cin >> students[i].grade;
        }
   }

void output() {
     for (int i=0; i<100; i++)  {
         cout << students[i].ID << endl;
         cout << students[i].name << endl;
         cout << students[i].grade << endl;
        }
   }

int main() {
    welcomeScreen();
    while (1) {
           int opt = displayMenu();
           switch (opt) {
                1: input(); break;
                2: output(); break;
               }              
     }
}


We have the main data -  Student students[100] - declared globally at the top. Now what's wrong (from a design perspective) with the code? We already made use of struct to gather related data. Can we do more? Looking at the functions, there are certainly functions that relate directly to students. In this example, input and output are the 2 functions related to students. Can we put them together?

Yes, we can. We can put related data and functions together in a struct, as shown below:

struct StudentList {
    Student students[100];

     void input() {
         for (int i=0; i<100; i++)  {
            cin >> students[i].ID;
            cin >> students[i].name;
            cin >> students[i].grade;
            }
       }

     void output() {
         for (int i=0; i<100; i++)  {
              cout << students[i].ID << endl;
              cout << students[i].name << endl;
              cout << students[i].grade << endl;
             }
       } 
}

We then can declare a variable of type StudentList, and this variable will contain all data and functions related to a list of students:

StudentList studList;

The main function would then be modified as follows:

int main() {
    welcomeScreen();
    while (1) {
           int opt = displayMenu();
           switch (opt) {
                1: studList.input(); break;
                2: studList.output(); break;
               }              
     }
}

The Truth about Struct in C++


That struct, the one we've seen - it's a class, the stuff that we're going to look at, focus at, all throughout this course. But it's not a real class of course, because it's lacking many other features that is needed for a full blown object-oriented programming, OOP. Still, it illustrates a key idea in OOP: we group together related data and functions. And we are about halfway to Encapsulation.

That will be in another post.


No comments:

Post a Comment