strnotes
strnotes
strnotes
UNIT-V:
STRUCTURES & UNIONS
Contents:
5.1. Introduction
5.2. Features of structures
5.3. Declaration and Initialization of structures
5.4. Nested structures
5.5. Array of structures
5.6. Arrays within Structures
5.7. Structures and Functions
5.8. Pointers to structures
5.9. typedef & Enumerated data types
5.10 Size of structures
5.11. Bit fields
5.12. Unions
5.13. Self-Referential Structures
5.14. Objective type questions
5.15. Descriptive type questions
Objective:
Structures provide a way to organize related collection of data. Unlike arrays,
structures allow organization of collection of variables with different data types. Unions
also provide a way to organize related data, but only one item within the union can be
used at a time. The structures and unions in C language are discussed in this unit.
5.1. Introduction:
We have seen that arrays can be used to represent a group of data items that
belong to the same type, such as int or float. However we cannot use an array if we want
to represent a collection of data items of different types using the single name. C supports
a constructed data type known as Structures, a mechanism for packing data of different
types. The concept of a structure is analogous to that of a record in many other languages.
Ex:
Time Seconds (int), Minutes (int), Hours (float)
Date Day (int), Month (string), Year (int)
Book Author (string), Title (string), Price (float)
Address Name (string), Door_number (string), Street(string),City(string)
In the above example, book_bank is the name of the structure and it is called as
the structure-tag. It may be used subsequently to declare structure variables, which have
the specified tag’s structures.
Note that the above definition has not declared any structure variables. It simply
describes a format called as template.
The tag-name may be used to declare variables that have the tag structure.
Note that the above declaration has not declared any variables. It simply describes
a format called ‘template’.
The template is terminated with a semicolon.
typedef struct
{
type member1;
type member 2;
……………….
} type_name;
clrscr();
printf(“ Enter a person details:\n\n”);
printf(“ Enter person name : “);
scanf(“%s”,person.name);
printf(“Enter a person joining day : “);
scanf(“%d”,&person.day);
printf(“Enter a person joining month: “);
scanf(“%d”,&person.month);
printf(“Enter a person joining year: “);
scanf(“%d”,&person.year);
printf(“Enter a person salary: “);
scanf(“%d”,&person.salary);
printf(“\n\n person’s name is : %s\n”,person.name);
printf(“\n\n person’s joining day is : %s\n”,person.day);
printf(“\n\n person’s joining month is : %s\n”,person.month);
printf(“\n\n person’s joining year is : %s\n”,person.year);
printf(“\n\n person’s salary is : %s\n”,person.salary);
}
OUTPUT:
Enter a person details:
Enter a person name: Srinivas
Enter a person joining day: 9
Enter a person joining month: November
Enter a person salary: 5260.97
Enter a person joining year: 1997
Person’s name is : Srinivas
Person’s joining day is: 9
Person’s joining month is: November
Person’s joining year is: 1997
Person’s salary is :5260.970215
C language does not permit the initialization of individual structure members within
the template.
The initialization must be done only in the declaration of the actual variables.
Two variables of the same structure type can be compared the same way as
ordinary variables. If person1 and person2 belongs to the same structure, then the
fallowing operations are valid:
person1 = person2; ------ assigns person1 to person2
person2 = person1; ------ assigns person2 to person1
However, the statements such as,
person1 = = person2
person1! = person 2 are not permitted.
C does not permit any logical operations on structure variables. In such cases, we
need to compare them by comparing the members individually.
/*PROGRAM TO ILLUSTRATE THE COMPARISION & COPYING OF
STRUCTURE VARIABLES*/
#include<stdio.h>
struct class
{
int no;
char name[20];
float per;
};
main()
{
int x;
struct class stu1={111,”Ramu”,72.50};
struct class stu2={222,”Reddy”,67.00};
struct class stu3;
stu3=stu2;
if(stu2.no==stu3.no&&stu2.per==stu3.per)
printf(“\n student2 and student3 are same\n”);
else
printf(“\n student2 and student3 are different\n”);
}
We can also apply the increment and decrement operators to numeric type
members. For example, the following statements are valid:
stu1.no++;
++ stu2.no;
Note:
The precedence of the member operator is higher than all arithmetic and relational
operators and therefore no parenthesis are required.
We can also use tag names to define inner structures. For example,
struct pay
{
int da;
int hra;
};
struct salary
{
char name[10];
struct pay allowance;
struct pay arrears;
};
struct salary employee [100];
Here, pay template is defined outside the salary template and is used to define the
structure of allowance and arrears in side the salary structure.
Note:
C permits nesting up to 15 levels. However, C99 allows 63 levels of nesting.
defines an array called ‘student’ that consists of 100 elements. Each element is defined
to be of the type struct class.
struct marks
{
int eng;
int tel;
int sci;
};
main( )
{
struct marks student[3]={45,76,87},{78,68,79},{34,23,14};
…………….
…………….
}
This declares the student as an array of three elements student [0], student [1],
student [2] and initializes the members as follows:
student[0].eng=45;
student[0].tel=76;
…………………..
…………………..
student[2].sci=14;
Ex: 1
/*WRITE A PROGRAM TO CALCULATE THE SUBJECT-WISE AND
STUDENT-WISE TOTALS AND STORE AS A PART OF THE STRUCTURE*/
#include<stdio.h>
struct marks
{
int eng;
int tel;
int sci;
int tot;
};
main( )
{
int i;
struct marks student[3]={{45,67,81,0},{75,53,69,0},{57,36,71,0};
struct marks t;
for(i=0;i<3,i++)
{
student[i].tot=student[i].eng+student[i].tel+student[i].sci;
t.eng=t.eng+student[i].eng;
t.tel=t.tel+student[i].tel;
t.sci=t.sci+student[i].sci;
t.tot=t.tot+student[i].tot;
}
printf(“ STUDENT TOTAL \n\n”);
for(i=0;i<3;i++)
printf(“ stu[%d] : %d\n”,i+1,stu[i].tot);
printf(“ SUBJECT TOTAL\n\n”);
printf(“English : %d\n Telugu : %d\n Science :
%d\n”,t.eng,t.tel,t.sci);
printf(“\n Grand total : %d\n”,t.tot);
getch( );
}
Ex 2:
/* Write a program to enter 5 dates. Store this information in array of structures*/
#include<stdio.h>
struct date
{
int day, year;
char month[10];
} b_days [5];
main( )
{
int i;
for(i=0;i<5;i++)
{
printf(“\nEnter 5 dates:”);
scanf(“%d %d %s”,&b_days[i].day, &b_days[i].year, b-days[i].month);
}
for(i=0;i<5;i++)
{
printf(“\nbirth day dates are %d %d %s”, b_days[i].day, b_days[i].year,b_days[i].month);
}
}
Note:
An array of structures is stored in memory in same way as a multi-dimensional array.
/
***********************************************************************
Ex 1: Rewrite the program of above example 1 using an array member to represent
the three subjects.
************************************************************************
main( )
{
struct marks
{
int sub[3];
int total;
};
struct marks student[3]= {45,67,81,0,75,53,69,0,57,36,71,0};
struct marks total;
int i,j;
for(i=0;i<=2;i++) /* ‘i’ represent student*/
{
for(j=0;j<=2;j++) /* ‘j’ represent subjects */
{
student[i].total+=student[i].sub[j];
total.sub[j]+=student[i].sub[j];
}
total. total= student[i].total;
}
printf(“\nSTUDENT TOTAL\n\n”);
for(i=0;i<=2;i++)
printf(“student[%d] %d\n”, i+1,student[i].total);
printf(“\nSUBJECT TOTAL\n\n”);
for(j=0;j<3;j++)
printf(“subject-%d %d\n”,j+1,total.sub[j]);
printf(“\nGrand Total = %d\n”, total.total);
The first method is to pass each member of the structure as an actual argument of
the function call. The actual arguments are then read independently like ordinary
variables. This is the most elementary approach and becomes unmanageable and
inefficient when the structure size is large.
The second method involves passing of a copy of the entire structure to the called
function [Like, call by value]. Since the function is working on a copy of the
structure, any changes to the structure members within the function are not
reflected in the original structure. Therefore, it is necessary for the function to
return the entire structure back to the calling function.
Note: All the compilers may not support this method of passing the entire
structure as a parameter.
The third approach employs a concept called pointers to pass the structure as an
argument. In this case, the address location of the structure is passed to the called
function. The function can access indirectly the entire structure and work on it.
This is similar to the way, arrays are passed to functions. This method is more
efficient as compared to the second one.
i) The called function must be declared for it’s type, appropriate to the data type
it is expected to return. For example, if it is returning a copy of the entire
structure, then it must be declared as struct with an appropriate tag name.
ii) The structure variable used as the actual argument and the corresponding
formal argument in the called function must be of the same struct type.
iii) The return statement is necessary only when the function is returning some
data. The expression may be any simple variable or structure variable or an
expression using simple variables.
iv) When a function returns a structure, it must be assigned to a structure of
identical type in the calling function.
v) The called function must be declared in the calling function, if it is placed
after the calling function.
Ex 1:
Write a simple program to illustrate the method of sending an entire structure as a
parameter to a function.
/***********************************************************************
Passing a copy of the entire structure as an argument to a function
***********************************************************************/
#include<stdio.h>
#include<conio.h>
struct stores
{
char name[20];
float price;
int qty;
};
main( )
{
struct stores update(struct stores,float,int); /*function prototype*/
float mul(struct stores); /*function prototype*/
float p_inc,val;
int q_inc;
struct stores item={"pen",5.50,10};
clrscr();
printf("Price :%f\n",item.price);
printf("Quantity :%d\n",item.qty);
val=mul(item); /*function call*/
printf("\nValue of the item=%f\n",val);
getch();
}
Note: Template of ‘stores’ is defined before main( ) function, i.e., the data type ‘struct
stores’ is defined as global and has enabled the functions ‘update & mul’ to make
struct inventory
{
char name[30];
int number;
float price;
}product[2], *ptr;
This statement declares that, product as an array of 2 elements, each of the type
‘struct inventory’ and ‘ptr’ as a pointer to the data objects of the type ‘struct inventory’.
The assignment statement
ptr = product;
would assign the address of 0th element of ‘product’ to ‘ptr’. That is, the pointer ‘ptr’
points to ‘product [0]’. It’s members can be accessed using the following notation.
ptr -> name;
ptr->number;
ptr->price;
The symbol ‘->’ is called as the arrow operator and it is comprised of a minus
sign & a greater than sign. Note that ptr-> is simply another way of writing product [0].
Whenever the pointer is incremented by one, it is made to point to the next record,
i.e., product[1].
We could also use the following notation,
(*ptr).name to access the member ‘name’.
Note: The parenthesis around ‘*ptr’ are necessary because, the member operator (.) has
higher precedence than the operator ‘*’.
While using the structures pointers, we should take care of the precedence of
operators. The operators ‘->’, ‘.’, ( ), [ ] have the highest priority among the operators.
They bind very tightly with their operands. For example, consider the following
definition:
struct xyz
{
int count;
float *p; /* Pointer inside the struct xyz */
} *ptr; /* struct xyz type pointer */
Ex 1:
/*EXAMPLE PROGRAM ON STRUCTURE POINTERS*/
#include <stdio.h>
main( )
{
struct book
{
char title[25];
char author[25];
int no;
};
struct book b={“ RGM ‘C’ Notes”,”DCSE”,9};
struct book *ptr;
ptr=&b;
printf(“%s %s %d\n”,b.tittle,b.author,b.no);
printf(“%s %s %d\n”, ptr->tittle,ptr->author,ptr->no);
}
Output:
RGM C Notes DCSE 9
RGM C Notes DCSE 9
Explanation: The first printf( ) is as usual way of accessing the members of the structure.
The second printf( ) however is peculiar. We cannot use ptr.tittle, ptr.author and ptr.no
because ptr is not a structure variable but it is a pointer to a structure, and the dot operator
requires a structure variable on its left. So, In such cases C provides an operator -> called
as an arrow operator to refers the structure elements.
NOTE:
b.no This notation is used, whenever you’re already got the address
of the content of the member ‘no’.
b->no This notation is used, whenever you’re got the pointer to the
address, where the actual content (i.e., ‘no’) is stored.
[Both notations will gives the value of the member ‘no’.]
Ex 2:
/*EXAMPLE PROGRAM ON PASSING ADDRESS OF A STRUCTURE
VARIABLE */
#include<stdio.h>
main( )
{
struct book
{
char title[25];
char author[25];
int no;
};
struct book b={“ RGM ‘C’ Notes”,”DCSE”,9};
clrscr();
display(&b);
}
display(struct book *b)
{
printf(%s\n %s\n %d\n”,b->tittle,b->author,b->no);
}
OUTPUT:
RGM ‘C’ notes
DCSE
9
struct invent
{
char name[20];
int number;
float price;
}
main( )
{
struct invent product[3], *p;
clrscr( );
printf(“\n INPUT \n\n”);
for( p = product; p<product+3; p++)
scanf(“%s %d %f”,p->name, &p->number, &p->price);
printf(“\nOUTPUT\n\n”);
p=product;
while(p < product +3)
{
printf(“%-20s %5d %11.5f\n”, p->name, p -> number, p ->price);
p++;
}
getch( );
}
i) typedef
The users can define an identifier that represent an existing data type by a feature
known as “type definition”. The user defined data type identifier can later be used to
declare variables.
General form:
Where type refers to an existing data type and identifier refers to the new name
given to the specified data type.
Ex:
typedef int sno;
typedef float salary;
Here sno symbolizes as int and salary symbolizes as float. These can be used to
declare variables as follows.
sno c1,c2;
salary e1,e2;
Note: The main advantage of typedef is that we can create meaningful data type names
for increasing the readability of the program.
General form:
enum identifier {value 1, value 2, ……, value n};
The identifier is a user defined enumerated data type which can be used to declare
variables that can have one of the values which are enclosed within the braces. After that
we can declare variables to be of this new type.
enum identifier v1, v2, ….vn;
The enumerated variables v1, v2, …..,vn can only have one of the values, such as
value 1, value 2, ……value n.
Ex 1:
enum month {january, february, ….december};
enum month month_st, month_end;
(or)
enum month {january, february, …., December} month_st, month_end;
Here the declaration and definition of enumerated variables can be combined in
one statement.
Ex 2:
enum day{Monday,Tuesday……Sunday};
enum day week_st,week_end;
week_st=Monday;
week_end=Friday;
if(week_st==Tuesday)
week_end=Saturday;
The compiler automatically assigns integer digits beginning with 0 to all the
enumeration constants. That is, the enumeration constant Monday is assigned with 0,
Tuesday is assigned with 1 and so on. However, the automatic assignments can be
overridden by assigning values explicitly to the enumeration constants.
For example,
enum day{Monday=1,Tuesday, ……., Saturday};
here, the constant Monday is assigned the value 1.The remaining constants are assigned
values that increases successively by 1.
We normally use structures and arrays to create variables if larger sizes. The
actual size of these variables in terms of bytes may change form machine to machine. We
may use the unary operator sizeof to tell us the size of a structure.
The expression sizeof(struct x) will evaluate the number of bytes required to hold
all the members of the structure x.
If y is a simple structure variable of type struct x, then the expression sizeof (y)
would also give the same answer.
Bit fields are the special features provided in ‘C’ to change the order of allocation
of memory from bytes to bits. Generally, we are using integer fields of size 16 bits to
store data. There are some occasions where data items require much less than 16 bits
space. In such cases, we waste memory space.
General format of bit field definition:
struct tag_name
{
data type var_name1:bit_length;
data type var_name2:bit_length;
---------------------------------------
---------------------------------------
};
Where,
data type is either int or unsigned int or signed int.
bit length is the number of bits used for the specified variable name.
Note: Signed bit field should have at least 2 bits (one bit for sign).
A bit field is a set of adjacent bits whose size can be from 1 to 16 bits in length.
The field name is followed by a colon.
Using bit fields we can specify the exact number of bits required for the storage
of values.
The name and size of bit fields are defined using a structure.
The bit length is decided by the range of value to be stored.
The largest value that can be stored is 2n-1. Where, n is the bit length.
The size of the field cannot exceed the number of bits required to store an integer
variable on the machine, for which the program is written.
No C compiler permits fields to be declared with non-integral types, such as
float and no compiler permits array of fields.
We can not take the address of a bit-field variable. This means we cannot use
scanf to read values into bit fields.
Pointers cannot be used to access the bit fields.
Bit-fields cannot e arrayed.
Bit fields cannot be the members of unions, but they can be members of the
structures which are themselves the members of unions.
It is possible to combine normal structure elements with bit-field elements.
Ex 1:
struct personal
{
unsigned age: 7 (range is 0 to 127)
unsigned m_status: 1 (0 or 1)
} employee;
The above example defines a structure variable ‘employee’ with two fields. Once
bit fields are defined, they can e referenced just as any other structure-type data item
would be referenced. The following assignment statements are valid.
employee.age = 28;
employee.m_status = 1;
Ex 2: /*Using bit fields, Write a C program to store the information of vehicles.*/
#include<stdio.h>
main( )
{
struct vehicle
{
unsigned type: 3;
unsigned fuel: 2;
unsigned model: 3;
} V;
V.type=4;
V.fuel=2;
V.model=6;
printf(“Type of vehicle:%d\n”, V.type);
printf(“Fuel is %d\n”, V.fuel);
printf(“Model is %d\n);
getch( );
}
Ex 3:
struct vehicle
{
unsigned type: 3;
unsigned model: 3;
unsigned : 2; /* These two bits are reserved in the structure, but
it can not be accessed, because it has no name*/
int reg_ no:
} V;
Integer member must start at beginning of the new byte. In the above example,
type and model requires only 6 bits. If an integer member reg_no is declared by
following these two members, then reg.no starts from new byte, so, the remaining 2 bits
are unused.
The programmer has some control over alignment with in a structure declaration,
when only the size of bit field is specified, with no name, such as unsigned: 2.
5.12. Unions
Unions are a concept borrowed from structures and therefore it follows the same
syntax as structures. However there is major distinction between them is, in terms of
storage. In structures, each member has its own storage location, whereas all the members
of a union use the same location. This implies that, although a union may contain many
members of different types, it can handle only one member at a time. Like structures, a
union can be declared using the keyword union as follows.
General format:
union name
{
type var1;
type var2;
.
.
.
};
Ex:
union class
{
int marks;
float average;
char grade;
} student;
This declares a variable ‘student’ of type union ‘class’. The union contains three
members each with a different data type.
However we can use only one of them at a time. This is due to the fact that only
one location is allocated for a union variable, irrespective of its size.
1
grade
2
marks
4
average
Fig: Sharing of a storage locating by union members
The compiler allocates a piece of storage that is large enough to hold the largest
variable type in the union. In the declaration above the member ‘average’ requires 4 bytes
which is the largest among the members. The above figure shows how all the three
variables share the same address.
Consider an example:
struct conditions
{
float temp;
union feels_like
{
float wind_chill;
float heat_index;
}
} today;
As you know, wind_chill is only calculated when it is "cold" and heat_index
when it is "hot". There is no need for both. So when you specify the temp in today,
feels_like only has one value, either a float for wind_chill or a float for heat_index.
Types inside of unions are unrestricted; you can even use structs within unions.
st.set.f = 5.5;
st.set.p[0]= 65;
st.set.p[1]=66;
clrscr();
printf(“\n%f\t%c\t%c”, st.set.f,st.set.p[0],st.set.p[1]);
getch( );
}
Unions may be initialized when the variable is declared, but, unlike structures, it
can be initialized only with a value of the same type as the first union member. Other
members can be initialized by either assigning values or reading from the keyboard.
One restriction on structure nesting is that, a structure can not contain an image of
itself. That is, a structure cannot contain a member defined with the same tag as the
outside structure. Such a construct would leads to an infinite recursion.
A structure contains a member, which is a pointer to the structure of same type.
Such a kind of structure is known as “Self-referential structure”. (OR) In other words, as
the name suggests, a self-referential structure references itself through one of it’s member
elements.
Ex:
struct card
{
char title[30];
char author[30];
struct
{
char month[3];
int day;
int year;
} date;
int no_copies;
struct card *next_card; /* Points to the next card in the catalogue */
} one_card;
In the above example, each card structure contains a member, that is a pointer to
another card structure. This does not cause infinite recursion, since a pointer to a structure
does not physically contain any member, it is used to hold the address of another card
structure.
Suppose, we wish to refer the title member of the structure to which
one_card.next_card points.
Note:
i) Both dot (.) and arrow (->) have the same precedence.
ii) Linked list is one of the typical applications of self-referential structure.
Pointers to remember:
Structures Review
Structures can store non-homogenous data types into a single collection, much like an array does
for common data (except it isn't accessed in the same manner).
Pointers to structs have a special infix operator: -> for dereferencing the pointer.
typedef can help you clear your code up and can help save some keystrokes.
Enumerated types allow you to have a series of constants much like a series of #define statements.