ITP week 7
ITP week 7
Reading Objective:
In this reading, you will learn about user-defined data types in C. You will also learn how to create your own
data and how to use them in programming.
Until now, we have seen a lot of built-in data types in C, such as int, float, and char, etc. These data types
can represent integers, real numbers, characters, and strings. We can also create arrays of these data types.
But now, let us consider a diverse group of data items that are somehow related to each other. For example,
let us take a student database, where each student has an associated ID, name, and CGPA. How would we
implement this database in C?
Based on what we have learned so far, we could create three different arrays as follows:
Now, for each student, we have stored their data in three separate arrays. If we have to add or delete a
student’s records, it has to be done separately in all three arrays. Moreover, it would require three
parameters to pass a student’s data into a function. Also, there is no real linkage between the ID and the
name of the student in our code.
Consider another example—say we want to represent a point in a three-dimensional space. This can be
done by specifying the x, y, and z coordinates. If we want to store a bunch of such points, we would have to
create three different arrays again:
Would not it be much better if we were able to represent a Point or a Student as one single entity, just as it
is in real life? Fortunately, C offers this functionality! We can design our own custom data types using the
struct keyword in C.
Structures in C
A structure is a data type that is designed by the user. It is a combination of primitive data types, such as
int, float, char, or bool.
Let us now try to define the structures we discussed in the previous sections:
Now that we have defined the structure using the struct keyword, we can declare structure variables just
like we declared variables of primitive data types. The only difference is that a struct keyword is required
whenever declaring a variable, as follows:
Now, s1 is a Student variable and has associated attributes: ID, name, and CGPA. Similarly, p1 and p2 are
point variables.
We can access members of a struct using the dot operator. For example, it is possible to access the ID of
student s1 as s1.ID.
As another example, we can also directly transfer values into the structure by taking input. Consider the
following code snippet:
This takes the student’s ID, name, and CGPA as input and stores them in their respective attributes inside
the student structure.
We can specify all attributes of a structure during initialization itself as comma-separated entries inside
curly braces:
Operations on Structures
Not many operations can be performed on structures as a whole in C. The only possible operators that can
be used with structures are =, dot, ->, and &. Equals (‘=’) is the assignment operator. Assignment works just
as in the case of primitive data types.
For example, s1 = s2 will give all attributes of s1 the same value that they had in s2. Similarly, & retains its
usual significance with structures. However, dot (‘.’) and arrow (‘->’) are operators exclusively meant for
accessing members of a structure.
Note that we cannot use any other operations with structures. We cannot add two structures together, or
find their bitwise XOR, or check equality using ‘==’.
Question: If the ‘==’ operator is not allowed to be used with structures, how can we check if two
structures are equal?
It seems unnecessarily lengthy, typing “struct” before every variable declaration, does not it? Fortunately,
C has a feature that can bypass this! The keyword typedef can create a simple synonym for the words struct
<struct_name>, as follows:
The typedef keyword here basically does this: whenever “stu” is encountered in the code, the compiler will
internally convert it to “struct Student.” This saves time for us as we have to type less code!
Reading Summary:
• How to define structures and create structure variables (usage of the struct keyword)
• How to access members of a structure and other possible operations with structures
• How to use typedef to improve readability and reduce typing effort in coding
Practice Lab 1: Structures in C
Assignment Brief
Create a Point structure as taught in the lectures. Then, create two-point objects representing the points (3,
2) and (−1, −5). Print the x-coordinate and y-coordinate of the points to standard output.
Create a structure called Employee. It should contain the ID, name, and job of the employees. Read the ID,
first name, and job of three employees as input, and print the details of the employee whose ID is 2.
Testcase1
Input:
Output:
Write a program that takes two distances as input. The distances are in the form of X kilometers and Y
meters.
For example, 23 68 means 23 kilometers and 68 meters. Store the distances in a structure. After that, find
the difference between the two distances. Store this difference in another structure(1,000 meters = 1
kilometer). It is guaranteed that the second distance is greater than the first distance.
A structure definition has been provided, complete the missing parts of the code!
Testcase1 Testcase2
Input: Input:
Output: Output:
The difference is = 5 kilometers and 20 meters The difference is = 0 kilometers and 500 meters
Reading: More Structures
Reading Objective:
In this reading, you will learn about nested structures and how to create arrays of structures.
Nested Structures
A structure can even contain other structures as attributes. A structure can have another structure, and the
inner structure can contain more structures as its members, and so on. This can help in modeling more
complex data.
Example:
In this example, we created a struct Student that contains, as its members, two more structs, Address, and
name.
Question: How can we access the last name of a student in the above definition?
Answer:
So, the dot operator can be used multiple times to access inner struct data.
It is possible to create arrays of structures, just as we could create arrays of int, char, bool, etc. The
declaration is pretty straightforward. For example:
This creates an array of Student, of size 500. Now, let us say we want to access the CGPA of the 26th student
in this array. We can do that using stu_records[25]. CGPA (remember that arrays are 0-indexed, so the 26th
student would be at location 25!).
The functionality of structures can be enhanced using functions. Structures can be passed as parameters to
functions (both pass-by-value and pass-by-reference are supported) and can be returned from functions
too. For example, we can create a function to add two complex numbers together or to print the real and
imaginary parts of a complex number.
Reading Summary:
• Nested structures in C
• How to declare arrays of structures and access member variables while dealing with arrays of
structures
• How to pass structure variables as arguments to functions, and how to return structure variables
from functions
Practice Lab 2: More Structures
Assignment Brief
PracticeLab2_Question1
Write a program that takes N points in the x-y coordinate plane as input, and then print the point with the
maximum distance from the origin. Try to use structures in your program!
Hint: The distance of a point from the origin is equal to sqrt{x^2 + y^2}.
The input should be taken in the following format—the first line will contain only a single integer N as
input. After that, the next N lines will contain two real values each, first x coordinate then y coordinate.
Testcase1
Input:
45
1.5-1.5
05
Output:
PracticeLab2_Question2
The definition of the Complex structure is given in the file Question2.c, which is used to represent complex
numbers in C. Also, the function signature of the addition function is provided, to add two complex
numbers.
1. Complete the addition function, which should return the sum of the two complex numbers.
2. Create two new functions, subtract and multiply, which return the difference and product of the
two complex numbers respectively.
Note: You should not make any changes inside int main().
Hint: Given two complex numbers (a + ib) and (c + id), their sum is given by (a + c) + i(b + d), their
difference is given by (a − c) + i(b − d), and their product is given by (ac − bd) + i(ad + bc).
For example: If the complex numbers are (3 + 4i) and (7 + 12i), their sum is (10 + 16i), their difference is (−4
−8i), their product is (−27 + 64i).
PracticeLab2_Question3
Write a function that takes two dates as parameters, compares them, and returns which date is older.
1. You should make a structure called Date, and store both the dates in the structure.
2. You should make a function that takes two Dates as input and returns the larger Date.
3. Now, write a program so that it takes N = 10 dates as input, compares all of them, and prints the
oldest date.
Input will be given in the following format—each line will contain a new date in the form “D M Y.”
Testcase1
Input:
12 9 2002
27 1 2003
Explanation: The dates correspond to 12th September, 2002 and 27th January, 2003. The older date is
printed.
Reading: Example Cases
Reading Objective:
In this reading, you will learn about two comprehensive examples. The first one is on the point structure,
which is essential for coordinate geometry, and the second one is on a student record/database.
Question: Define a structure for representing two-dimensional (2D) grid points on a plane. Using
the structure, define functions to answer the following questions:
Answer: Let us start by defining the point structure and the function prototypes.
The function FindQuadrant will return 1/2/3/4 based on the quadrant the point lies in, and 0 if it lies on the
axes. Hint: see the figure given below.
We can implement the FindQuadrant function as follows:
Point to ponder: This function will return true even when both points are on the coordinate axes. How
would you change the function if the result should be false for points on coordinate axes?
Answer:
Question: Add the following functionality to the Point program created above.
• What is the distance between two given points?
Recall that the distance between two points is given by the equation:
We can implement this in code as follows (remember that we need to include math.h header file to use the
sqrt function!):
Also, recall that three points are collinear if the area of the triangle formed by them is 0. The area of the
triangle formed by three points is equal to:
Let us now write an example program to show how the code we just wrote would work. Try to write the
program in your local/online compiler and see if the outputs match.
Output:
Question: Define a structure for representing an array of students. Each student must have a
name, ID, and fields for marks in two subjects. Using the structure, write functions to:
• Print the name and ID of all students whose average marks are greater than 70.
Answer:
Output:
Abhinav 1 100.000000
Shivam 3 73.000000
Harsh 4 72.500000
Question: Modify the Student structure to store the date of joining for each student. Now, write
the functionality to:
• Print the name and ID of students whose date of joining is 2020 or later.
Answer: Date is not easy to represent using primitive data types. It is a combination of date, month, and
year. It makes sense to make a new structure for the date. We can now define our structures as follows:
The rest of the program is fairly straightforward after this:
Output:
Abhinav 1 21-1-2021
Manish 2 15-9-2020
Shivam 3 7-12-2020
Reading Summary:
Examples of various real-world applications of structures in C. In the first example, you represented points on a
two-dimensional (2D)cartesian plane as structures and performed various operations of coordinate geometry on
them. In the second example, you created a student database to store various details of students and performed
various queries on the database
Lesson 1: Structures in a C Program
WHAT TO LEARN
member can be a primary data type, an array or even another structure (or union). To accommodate
multiple structures having the same type, C also supports an array of structures.
The advantage of using a structure is strongly felt when it is used as an argument to a function.
It is more convenient to pass a structure containing all employee details as a single argument
to a function rather than pass its members as separate arguments. A function can also return
a structure, and if copying an entire structure bothers you, you can even pass a pointer to a structure
as a function argument. Structures present the best of both worlds as you’ll see soon.
Let’s now declare and define a structure comprising three members that contain information of
an audio CD sold in a store. This information is represented by the title, the quantity in stock and
the price. The following declaration creates a structure named music_cd:
User-Defined Data Types 447
Takeaway: Declaration of a structure creates a template but doesn’t allocate memory for the
members. Memory is allocated when variables based on this template are created by definition.
Note: The terms declaration and definition are often used interchangeably with structures.
This book, however, follows the convention adopted by Kernighan and Ritchie to create a template
by declaration and an instance (i.e., an actual object) by definition.
Form 1 Form 2
For an initialized structure, the variable name is followed by an = and a list of comma-delimited
values enclosed by curly braces. These initializers obviously must be provided in the right order.
In Form 2, “Beethoven” is assigned to title and 3 to qty.
You can create multiple variables and initialize them at the same time, as shown in the following
snippets which represent the last line of declaration:
} disk1, disk2, disk3;
} disk1 = {“Beethoven”, 3, 12.5}, disk2 = {“Mahler”, 4, 8.75};
Like with arrays, you can partially initialize a structure. If you initialize only title, the remaining
members, qty and price, are automatically assigned zeroes.
By default, uninitialized structures have junk values unless they are global. A structure defined
before main is a global variable, which means that the members are automatically initialized to
zero or NULL.
Note: The structure tag is necessary when a structure is declared and defined at two separate places.
User-Defined Data Types 449
int main(void)
{
struct music_cd { /* Declares structure for music_cd */
char title[27]; /* Member can also be an array */
short qty;
float price;
} disk1 = {“Bach”, 3, 33.96}; /* Defines and initializes ...
... structure variable disk1 */
printf(“The size of disk1 is %d\n”, sizeof disk1);
/* Using scanf */
fputs(“Enter the quantity and price for disk3: “, stdout);
scanf(“%hd%f”, &disk3.qty, &disk3.price);
printf(“%s has %hd pieces left costing %.2f a piece.\n”,
disk3.title, disk3.qty, disk3.price);
return 0;
}
Note that sizeof computes the total memory occupied by a structure. This is not necessarily
the sum of the sizes of the members. For reasons of efficiency, the compiler tries to align one or
more members on a word boundary. Thus, on this machine having a 4-byte word, title occupies
28 bytes (7 words) even though it uses 27 of them. qty and price individually occupy an entire
word (4 bytes each), but qty uses two of these bytes. disk1 thus needs 33 bytes (27 + 2 + 4) but it
actually occupies 36 bytes.
Alignment issues related to structures lead to the creation of slack bytes or holes in the allocated
memory segment (Fig. 14.1). If you reduce the size of the array to 26, no space is wasted and
sizeof disk1 evaluates to 32.
A B C D E FG H I J K LM N O P Q R S T U V W X YZA - - - 9 9 999 9
Slack bytes
A structure can be copied to another structure provided both objects are based on the same
template. The first statement in the following code segment defines a variable disk2 based
on a template declared earlier. The second statement uses the assignment operator to copy all
members of disk2 to disk3:
struct music_cd disk2 = {“mozart”, 20, 9.75};
struct music_cd disk3 = disk2;
This feature is not available with arrays; all array elements have to be copied individually.
No arithmetic, relational or logical operations can be performed on structures even when the operation
logically makes sense. It is thus not possible to add two structures to form a third structure
even if the members are compatible.
It is not possible to compare two structures using a single operator even though such comparison
could be logically meaningful. Each member has to be compared individually as shown by
the following code:
if (strcmp(disk2.title, disk3.title) == 0
&& disk2.qty == disk3.qty
&& disk2.price == disk3.price)
fputs(“disk2 and disk3 are identical structures\n”, stdout);
If a structure contains 20 members, you need to use 20 relational expressions to test for equality.
Unfortunately, C doesn’t support a better option.
When a structure is passed by name as an argument to a function, the entire structure is copied inside
the function. This doesn’t happen with arrays where only a pointer to the first element of
the array is passed. However, copying can be prevented by passing a pointer to a structure as
a function argument.
A member of a structure can contain a reference to another structure of the same type.
This property of self-referential structures is used for creating linked lists.
Barring the last attribute in the list, the other attributes will be examined in this chapter.
Self-referential structures are discussed in Chapter 16.
Takeaway: An array and structure differ in three ways: 1) A structure variable can be assigned
to another structure variable of the same type. 2) The name of a structure doesn’t signify
a pointer. 3) When the name of a structure is passed as an argument to a function, the entire
structure is copied inside the function.
You can now use new_name in place of data_type. Some of the declarations we have used previously
can now be abbreviated using typedef:
User-Defined Data Types 453
Form 1 Form 2
Form 1 combines the creation of the synonym named EXAMINEE with the declaration of student,
which is preceded by the keyword typedef. In this form, the structure tag (student) is optional and
can be dropped. But the second form creates the synonym after the declaration, so the tag is necessary.
EXAMINEE is now a replacement for struct student, so you can create variables of type EXAMINEE.
Note: typedef was not designed simply to replace data types with short names. It was designed to
make programs portable by choosing the right data types without majorly disturbing program
contents. If you need 4-byte integers, you can use typedef int INT32; to create a synonym in a special
file and then create variables of type INT32 in all programs. If the programs are moved to a machine
where int uses 2 bytes, you can simply change the statement to typedef long INT32; without disturbing
the contents of the programs. (The long data type uses a minimum of 4 bytes.)
int main(void)
{
typedef struct film { /* Declaration also creates synonym */
char title[30];
char director[30];
unsigned short year;
} MOVIE1; /* Synonym MOVIE1 created as a data type */
return 0;
}
Note: Even though film and cinema have identical members, they represent separate templates.
Their variables are thus not compatible for copying operations. It’s not possible to assign release1
(of type film) to release2 (of type cinema) or vice versa.
struct student {
char name[30]; Member 1
struct { Structure as member
short day;
short month;
short year;
} dt_birth; Member 2
int roll_no; Member 3
short total_marks; Member 4
};
struct student stud1;
Here, the declaration of the inner structure forms part of the declaration of the outer one. Note that
dt_birth is actually a variable to which its members are connected. However, you can’t separately
create a structure variable of this type. This restriction, however, doesn’t apply if the two structures
are declared separately. Define the inner structure before the outer one:
struct dob { dob must be declared before ...
short day;
short month;
short year;
};
struct student {
char name[30];
struct dob dt_birth; ... it is used in student.
int roll_no;
short total_marks;
};
struct student stud1;
struct dob dob1;
Encapsulating the three components of a date into a separate structure has two advantages over
using separate “unstructured” members. First, you can pass this structure to a function as a single
argument without losing the ability of individually accessing its members. Second, because dob
can be used by multiple programs, its declaration could be stored in a separate file. A program that
uses a date field as a three-member structure can simply include this file.
For every increment in the level of nesting, the number of dots increase by one. This dot-delimited
notation is similar to the pathname of a file. On Windows and UNIX systems, the pathname
a/b/c refers to a file named c having b as its parent directory, which in turn has a as its parent.
For a structure member, the name a.b.c can be interpreted in a similar manner: a and b must be
names of structures while c can never be one.
14.5.3 structure_nested.c: Program Using a Nested Structure
Program 14.4 uses a nested structure where the inner structure named dob is incorporated
as a member of the outer structure named student. This data type is typedef ’d to EXAMINEE and
used to create two variables, stud1 and stud2. stud1 is initialized but stud2 is populated by scanf.
Note the use of the flag 0 in the printf format specifier (%02hd). This flag pads a zero to the day
and month members of dt_birth to maintain the 2-digit width.
EXAMINEE stud2;
fputs(“Enter name: “, stdout);
scanf(“%[^\n]”, stud2.name); /* Possible to enter multiple words */
Could we not have used three short variables here? Yes, we could have, and added another two
variables if we wanted to include five subjects. But would you like to use five variables with five
statements or a single array in a loop to access all the marks?
Note: Besides providing clarity, the inner braces in the initializer segment allow the partial
initialization of array elements and members of nested structures.
i++;
fputs(“Enter name: “, stdout);
scanf(“%[^\n]”, bat[i].name);
FLUSH_BUFFER
fputs(“Enter team: “, stdout);
scanf(“%[^\n]”, bat[i].team);
imax = i;
for (i = 0; i <= imax; i++)
printf(“%-20s %-15s %3hd %.2f\n”,
bat[i].name, bat[i].team, bat[i].tests, bat[i].average);
return 0;
}
struct student {
char name[30];
int roll_no;
short marks;
} temp, stud[COLUMNS] = {
{“Alexander the Great”, 1234, 666},
{“Napolean Bonaparte”, 4567, 555},
{“Otto von Bismark”, 8910, 999},
{“Maria Teresa”, 2345, 777},
{“Catherine The Great”, 6789, 888}
};
return 0;
}
It’s impractical to provide large amounts of data in the program. In real-life, structure data are saved
in a file, with each line (or record) representing the data of members stored in an array element.
Chapter 15 examines the standard functions that read and write files and how they can be used in
handling data of structures.
Takeaway: A function using a structure as argument copies the entire structure. If the structure
contains an array, it too will be copied.
Caution: A program may run out of memory when using structures as arguments. A structure
containing numerous members and large arrays can lead to stack overflow and cause the program
to abort.
Program 14.8 computes the difference between two times that are input to scanf in the form
hh:mm:ss. The values are saved in two structure variables, t1 and t2, that are typedef ’d to
TIME. A third variable, t3, stores the returned value. Note that the mins operand is shared by the
equal-priority operators, -- and dot, but because of L-R associativity, no parentheses are needed.
int main(void)
{
TIME t1, t2, t3;
t3 = time_diff(t1, t2);
printf(“Difference: %hd hours, %hd minutes, %hd seconds\n”,
t3.hours, t3.mins, t3.secs);
return 0;
}
User-Defined Data Types 465
Since t3 now has three new values, it can be said that time_diff has “returned” three values.
This property of structures breaks the well-known maxim that a function can return a single
value using the return statement. We’ll use this property to provide an alternative solution to the
swapping problem.
Note: The dot has the same precedence as the increment and decrement operators, but it has
L-R associativity. Thus, in the expression t2.mins--, the dot operates on mins before the -- does,
so we don’t need to use (t2.mins)-- in the program.
Takeaway: The assignment property (=) of structures, because of which one structure variable
can be assigned to another, allows a function to change the original values of structure members
using their copies.