One of the main motivations in the development of computers was data processing. One of the earliest punched card machines (tabulation machine) were used to help process data for the 1890 U.S. Census. Thus in programming languages data types were so important, as there are tools and methods to process data according to their type. But real life data seems to be collection of different such data types. For example in a census, a person’s name, age, gender, address, occupation etc. all needs to be stored as a collection, but they are of different data types.
Arrays are of no use here because arrays can store collections of a single data type. So the inventors of C came up with structures, which is a composite data-type, used to store collection of variables of different data types in a contiguous (continuous) block of memory. So a single structure having an int, a char, and a string variable of 10 characters will take a memory of 4+1+10, i.e. 15 continuous bytes in the memory. Thus it can be viewed as a data-type which requires 15 bytes of memory. The address of the first byte can be accessed by the structure name or a pointer to it.
Structures are predecessors of classes. C was developed in early 1970’s. There was no C++ or object-oriented programming. But there were data and computers were meant to store/process them. The concept of classes was only starting to arise in parallel with other programming languages, but many of structure’s characteristics were carried over to subsequent programming languages’ constructs.
The dot operator: The members (variables) of a structure can be accessed by the dot (.) operator. If a structure called student has a variable called name, it can accessed as student.name where student is an instantiation of the structure student. This notation is seen in all languages that has classes and objects.
The arrow operator: The members (variables) of a structure can be accessed by the arrow (->) operator when the instantiations are pointers. Thus if we have a pointer p of the structure student then the name variable can be accessed by p->name. Although present in classes in C++, this operator is mostly seen in the php language.
Lets see a simple example program using structures.
In this program, we create a structure called student in line no.3 and assign three member variables, name, marks and grade. We instantiate a variable of this structure s1 in line no.10 inside the main function. We take input from the user and store it in the s1 variable by accessing its members by the dot operator. To access addresses we use & operator just like in any ordinary variable.
One important thing to mention is the space we use before %c in line no.19. This is because of how scanf works with char datatype. It doesn’t trim whitespaces, so we avoid the leading whitespace by taking the second character from the input. If this doesn’t make sense to you, just remember to put a space whenever you use scanf to take a char input from the user.
After taking the input we simply print those information on the screen in our desired format.
In this program, we define a custom data type for our structure called student, by using the keyword typedef in line no.3 and assign three member variables, name, marks and grade. It is important to name this custom data type at the end of curly braces (as in line7).
In this program, we plan to create an array of variables of this structure (custom data-type). That’s why we have written a function createStudent to create individual student variables. Student creation is similar to how we created in the previous program, but note this function’s return type. The function createStudent has a return type of student. The function returns the student that we just created in the function.
In the main program, we declare an array of students (here 2). In a for loop we call the createStudent function for each student element of the array, and assign the returned value into this array element. Then we simply print all the students using another for loop.
In the following program, we try to replicate a real life implementation, which would have been relevant in 1970’s to process student data in a school. This will illustrated programming concepts like:
1. User defined data-type.
2. Dynamic memory allocation and reallocation.
3. Infinite loops and conditional break statement.
4. Pointers to user defined data types and their uses.
First, we define a custom data type for our structure called student, like in the previous program, but we don’t return anything. The input parameter is a pointer of the user defined data-type student. In this function, we create a student variable, and store a copy of it in the memory location given by the input pointer.
In the main program, we take the number of students in a class from the user (e.g. class teacher). We then dynamically allocate the required memory using the malloc function. We can determine the size of an individual student variable using the sizeof operator, as shown in line no.29. We cast the returned void pointer into a student pointer and assign it to ptr. If you have doubt regarding malloc and dynamic memory allocation, read this blog, or comment below.
Since this is a pointer of type student, incrementing ptr by 1 will traverse the memory by the number of bytes needed to store one variable of student type. So we can do arithmetic operation on the pointer to traverse through all students. Using a for loop, we create individual students and pass the address allocated for each student as argument to createStudent function, as shown in line no.32.
After creating all the students, we give the user a choice to enter more students (one by one), with the help of an infinite loop. In this while loop, the initial condition is always true, because 1 represents true in C language. So the program always enters the loop at least once. The only way to exit the loop is by using a break statement(line no.40). As long as the user types ‘Y‘ to the prompt, the break statement is skipped and new students are created. When the user types any other character, the break statement executes and the program exits the loop.
Then using another for loop, and using pointer arithmetic, we display all the data on the screen. Note the use of arrow (->) operators here. This is because ptr is a pointer. Here the expressions (*ptr).name and ptr->name are equivalent. Extending this program, the student data can be processed to sort students by name, get average grade of the class, etc.
In the present era of classes and objects, structures seems a weak concept/implementation of the idea of prototyping varieties of data. But remember it was used in a time when OOP wasn’t invented yet and it was extremely useful. The concepts implemented in structures were improved upon to invent object oriented programming as we know it. By this blog, I don’t recommend to use structures in your applications, but learning the fundamentals of structures will help you understand classes and objects, and memory and performance of an application.
You can download the code here.
If you liked this article please comment and show your support and interest so that I’ll be motivated to continue this effort. Like our facebook page if you haven’t already. And if you have any questions please comment. I’ll try to reply all.