Lesson12-Structures, Unions, Enums and Bitfields
Lesson12-Structures, Unions, Enums and Bitfields
enumerations and 12
bitfields
0
Chapter Outline
Chapter Outline
“United we stand, divided we fall."
-- Aesop (620 -560 B.C.) Structures.
Structures.
Introduction.
Introduction.
Working with structures.
Working with structures.
Nested structures.
Nested structures.
Structures and arrays.
Structures and arrays.
Structures and pointers.
Structures and pointers.
Structures and functions.
Structures and functions.
We cannot afford to be separate. . . . We have
Unions.
to see that all of us are in the same boat. Unions.
-- Dorothy Height Enumerated data type.
Enumerated data type.
Bitfields.
Bitfields.
struct <tag>
{
<data type1> <member(s)>;
<data type2> <member(s)>;
:
:
<data typeN> <member(s)>;
};
In this syntax,
struct is the keyword. <tag>, an optional one, serves as a name for this structure. It is used to
declare variable of the same structure type. It should be a valid identifier. The first line of this
declaration is called as structure header.
In this example, the structure student consists of the members: rno and age as integers, name and sex as
of char type and fees as of type float. However, the tag and names of members can be used as ordinary
variables with out any conflict in a program. Usually, this declaration can be placed at the top of source
code file, i.e., before the main().
Point to ponder #2
Declaration of structure outside of all functions never makes it global.
In this syntax,
struct is the keyword. <tag> is the name of the structure. <var1, var2 … varN> should be valid
identifiers.
Ex: struct student stud1,stud2;
The above statement declares two structure variables of type student: stud1, stud2. Usually, this
statement can be placed in body of main(). Once the variables are created, memory will be allocated for
them. The size of each variable is the sum of all the sizes of members of structure.
Point
Ex: to ponder
typedef#3unsigned long int ULONG;
This The size
typeofULONG
dataquestion
Interview
a structure variable is not always equal to sum of sizes of all members of structure.
#3 provides a short and meaningful way to call the data type: unsigned long int.
http://pradeeppearlz.blogspot.com 4 variables.
Now, the new data type ULONG can be used to declare User-Defined Data types
ULONG a,b,c; // variables are of type unsigned long int
Interview question #4
Why the ‘sizeof’ operator does sometimes results larger size than the calculated size for a
structure?
Padding (also called as buffering) is an important issue associated with structures. There may be some
alignment requirements enforced by the environment. E.g., ints may require to be aligned at even
numbered addresses and longs at address numbers divisible by 4. This is because, enforcing such
alignment boundaries help increase the access speed of the data stored in the memory and treat them
as a unit. E.g., in 8086 systems, a word size is 2 bytes. If a word is stored (i.e., aligned to start) in an
even address, the bytes can be read at a time. On the other hand, if it starts at an odd address, it is
accessed by two reads- obvious efficiency/time degradation. This leads to padding of bytes in the
structure. Due to this padding, the value returned by sizeof may not equal to sum of sizes of individual
structure members.
In this syntax,
<structure_variable> is the variable that is declared earlier.
<member_name> is the name of the member inside the body of structure.
Ex: The members of structure student are accessed with the help of structure variable stud1 and stud2 as
follows:
stud1.rno=26; stud2.rno=4;
stud1.age=18; stud2.age=18;
strcpy(stud1.name,”vamsee”); strcpy(stud2.name,”Sujitha”);
stud1.sex=’m’; stud2.sex=’f’;
stud1.fees=27500.00; stud2.fees=27500.00;
stud1
sizeof(stud1)=2+2+15+1+4=24 bytes
rno (2bytes) age (2 bytes) name(15 bytes) sex (1 byte) fees(4 bytes)
13 18 Balaji m 27500.00
Note:
A structure variable may be initialzed by means of assigning another structure variable of similar type.
E.g.,
struct student stud3=stud2;
assigns the data of stud2 to stud3. But, the structure variable at the right side of the assignment
statement has to be declared and initialized before the assignment.
By using scanf() statement
The input statement scanf() can be used to initialize the members of structure variables. scanf() function
can take members as arguments. Each member can be preceded with dot operator that is preceded with
structure variable. While reading members from keyboard, there is no necessity of reading these in the
same order as they are in structure declaration.
Ex: The structure variable stud1 of structure type student can be used to read all the members of
structure as follows:
scanf(“%d%d%s\n%c%f”,&stud1.rno,&stud1.age,stud1.name,&stud1.sex,&stud1.fees);
http://pradeeppearlz.blogspot.com 6 User-Defined Data types
Program #1 Program #2
/* program to read 3 student details and /* program to read 2 Employee details and
print them*/ print them*/
#include<stdio.h> #include<stdio.h>
struct student main()
{ {
int rno,age; typedef struct employee
char name[15],sex; {
float fees; int empno,experience;
}; float salary;
main() char *ename,*designation;
{ }EMPRECORD;
struct student stud1,stud2;
struct student EMPRECORD e1,e2,e3;
stud3={3,18,”Sirisha”,’f’,27500.00};
printf(“\n enter first student rno , name , age , printf(“\n enter first employee number, name,
sex and fees”); designation, salary and work experience”);
scanf(“%d%s%d\n%c%f”,&stud1.rno, scanf(“%d%s%s%f%d”,&e1.empno,
stud1.name, &stud1.age, &stud1.sex, e1.ename, e1.designation, &e1.salary,
&stud1.fees); &e1.experience);
printf(“\n enter second student rno , name , age printf(“\n enter second employee number,
, sex and fees”); name, designation, salary and work
scanf(“%d%s%d\n%c%f”,&stud2.rno, experience”);
stud2.name, &stud2.age, &stud2.sex, scanf(“%d%s%s%f%d”,&e2.empno,
&stud2.fees); e2.ename, e2.designation, &e2.salary,
&e2.experience);
printf(“\n First student details”);
printf(“\n Roll number=%d”,stud1.rno); printf(“\n First employee details”);
printf(“\n Name=%s”,stud1.name); printf(“\n Employee number=%d”,e1.empno);
printf(“\n Age=%d”,stud1.age); printf(“\n Name=%s”,e1.name);
printf(“\n Sex=%c”,stud1.sex); printf(“\n Designation=%s”,e1.designation);
printf(“\n Fees=%f”,stud1.fees); printf(“\n Salary=%f”,e1.salary);
printf(“\n Work Experience=%d”,e1.experience);
printf(“\n Second student details”);
printf(“\n Roll number=%d”,stud2.rno); printf(“\n second employee details”);
printf(“\n Name=%s”,stud2.name); printf(“\n Employee number=%d”,e2.empno);
printf(“\n Age=%d”,stud2.age); printf(“\n Name=%s”,e2.name);
printf(“\n Sex=%c”,stud2.sex); printf(“\n Designation=%s”,e2.designation);
printf(“\n Fees=%f”,stud2.fees); printf(“\n Salary=%f”,e2.salary);
printf(“\n Work Experience=%d”,e2.experience);
printf(“\n Third student details”);
printf(“\n Roll number=%d”,stud3.rno); e3=e2;
printf(“\n Name=%s”,stud3.name); printf(“\n copied employee details”);
printf(“\n Age=%d”,stud3.age); printf(“\n Employee number=%d”,e3.empno);
printf(“\n Sex=%c”,stud3.sex); printf(“\n Name=%s”,e3.name);
printf(“\n Fees=%f”,stud3.fees); printf(“\n Designation=%s”,e3.designation);
printf(“\n Salary=%f”,e3.salary);
} printf(“\n Work Experience=%d”,e3.experience);
}
Array size is known at the time of declaration. The members and their respective data types
are known at the time of declaration.
An array name represents the address of The structure name is not the base address.
starting element (or base address).
The array elements are accessed by its name The members of the structure are accessed by
followed by the square brackets [] within using the dot operator. The following form will
which the index is placed. be helpful to access the members:
Ex: a[3] is used to access the 4th element in <structure_variable>.<member_name>
the array. Ex: stud1.age is used to access the member
age.
An array can not have bit fields. A structure can have bit fields.
http://pradeeppearlz.blogspot.com 8 User-Defined Data types
12.1.3. Structure within a structure (Nested structure)
A structure can also be placed as a member in another structure. This can be done in two ways:
1. Place entire structure declaration along with structure variable in a structure (or)
2. Declare structure individually and place the structure variable in another structure.
The following example demonstrates this:
Method-1 Method-2
struct student //outer structure struct date_of_birth
{ {
int rno,age; int dd,mm,yy;
char name[15],sex; };
float fees; struct student
struct date_of_birth //Inner structure {
{ int rno,age;
int dd,mm,yy; char name[15],sex;
}dob; float fees;
}stud1,stud2; struct date_of_birth dob;
//structure variable of structure date_of_birth
}stud1,stud2;
Once the nested structure is declared, the inner structures become the members of outer structure. By
using the structure variable of outer structure, the inner structures variables get accessed. As dot operator
indicates membership, it should be used in between outer structure variable and inner structure variables
in order to access the members of inner structure.
e.g., In order to access the members of structure date_of_birth, the structure variables dob and stud1 are
used as follows:
stud1.dob.dd=8;
stud1.dob.mm=3;
stud1.dob.yy=1983;
Program #3 Program #4
/* program to read 3 student details and /* program to read 2 Employee details and
print them*/ print them*/
#include<stdio.h> #include<stdio.h>
struct student main()
{ {
int rno,age; struct address
char name[15],sex; {
float fees; char *street,*area,*city;
struct date_of_birth long int pincode;
{ };
int dd,mm,yy; typedef struct employee
}dob; {
}; int empno,experience;
main() float salary;
{ char *ename,*designation;
struct student stud1,stud2; struct address add;
struct student stud3={14,18,”amrutha”, }EMPRECORD;
’f’,27500.00,12,3,1991};
printf(“\n enter first student rno , name , age , EMPRECORD e1,e2,e3;
sex,fees”);
scanf(“%d%s%d\n%c%f”,&stud1.rno, printf(“\n enter first employee number, name,
stud1.name, &stud1.age, &stud1.sex, designation, salary and work experience”);
&stud1.fees); scanf(“%d%s%s%f%d”,&e1.empno,
printf(“\n Enter date-of-birth”); e1.ename, e1.designation, &e1.salary,
main()
{
printf(“\n Enter student rno,name”);
scanf(“%d%s”,&stud1.rno,stud1.name);
printf(“\n Enter student 3 subjects marks:”);
for(i=0;i<3;i++)
scanf(“%d”,&stud1.marks[i]);
stud1.total=0;
for(i=0;i<n;i++)
{
printf(“\nSubject%d=%d”,i+1,stud1.marks[i]);
stud1.total+=stud1.marks[i];
}
2. Secondly, Initialize that structure pointer with the address of a structure variable.
struct student std1;
stdptr=&std1; //initialization
Point to ponder #4
Pointer-to-structure holds the address of first byte of first member in structure declaration.
3. Finally, access the members of that structure using structure pointer as follows:
Method-1 (by using arrow operator) Method-2 (by using Indirection operator)
stdptr->rno=28 (*stdptr).rno=28
strcpy(stdptr->name,”Harish”); strcpy((*stdptr).name,”Harish”);
stdptr->sex=’m’; (*stdptr).sex=’m’;
stdptr->fees=27500.00; (*stdptr).fees=27500.00;
stdptr->dob.dd=12; (*stdptr).dob.dd=12;
stdptr->dob.mm=03; (*stdptr).dob.mm=03;
stdptr->dob.yy=1991; (*stdptr).dob.yy=1991;
Interview question #6
The way mentioning the array name or function name with out [] or () yields their base
address, what do you obtain on mentioning structure name?
The entire structure itself and not its base address.
if(firstnode==NULL)
firstnode=newnode;
else
prevnode->next=newnode;
prevnode=newnode;
scanf(“%d”,&value);
}
printf(“\n The Linked list:Head->”);
while(firstnode!=NULL)
{ printf(“%d->”,firstnode->data);
firstnode=firstnode->next;
}
printf(“NULL”);
}
for(i=0;i<n;i++)
stud=(struct student *)malloc(n*sizeof(struct student));
for(i=0;i<n;i++)
{
printf(“\n enter student %d rno , name , age , sex,fees”,i+1);
scanf(“%d%s%d\n%c%f”,&stud[i].rno, stud[i].name, &stud[i].age, &stud[i].sex, &stud[i].fees);
printf(“\n Enter date-of-birth”);
scanf(“%d%d%d”,&stud[i].dob.dd,&stud[i].dob.mm,&stud[i].dob.yy);
}
printf(“\n======================================================”);
printf(“\nRno\tName\tAge\tSex\tfees\tdate-of-birth”);
printf(“\n======================================================”);
for(i=0;i<n;i++)
{
printf(“\n%d\t%s\t%d\t%c\t%f\t%d/%d/%d”, std[i].rno,stud[i].name,stud[i].age,stud[i].sex,
stud[i].fees,stud[i].dob.dd,stud[i].dob.mm, stud[i].yy);
}
printf(“\n======================================================”);
}
COMPLEX add(COMPLEX,COMPLEX);
COMPLEX sub(COMPLEX,COMPLEX);
COMPLEX mul(COMPLEX,COMPLEX);
COMPLEX div(COMPLEX,COMPLEX);
main()
{
COMPLEX c1,c2,c3;
for(i=0;i<n;i++)
{ printf(“\n enter student %d rno , name , age , sex,fees”,i+1);
scanf(“%d%s%d\n%c%f”,&stud[i].rno, stud[i].name, &stud[i].age, &stud[i].sex, &stud[i].fees);
printf(“\n Enter date-of-birth”);
scanf(“%d%d%d”,&stud[i].dob.dd,&stud[i].dob.mm,&stud[i].dob.yy);
}
display(stud,n);
}
void display(struct student stud[15],int n)
{ printf(“\n=================================================”);
printf(“\nRno\tName\tAge\tSex\tfees\tdate-of-birth”);
printf(“\n=================================================”);
for(i=0;i<n;i++)
{printf(“\n%d\t%s\t%d\t%c\t%f\t%d/%d/%d”,std[i].rno,stud[i].name,stud[i].age,stud[i].sex,
stud[i].fees, stud[i].dob.dd,stud[i].dob.mm, stud[i].yy);
}
printf(“\n=================================================”);
}
EMPRECORD e[10];
EMPRECORD *temp;
int i,n;
for(i=0;i<n;i++)
{
printf(“\n enter %d employee number, name, designation, salary and work
experience”,i+1);
scanf(“%d%s%s%f%d”,&e[i].empno, e[i].ename, e[i].designation, &e[i].salary,
&e[i].experience);
Programming Examples
1) /*A menu-driven program to process student records (using array of structures)*/
#include<stdio.h>
struct student
{
int rno,rank;
char name[15];
struct date_of_birth
{
int day,month,year;
}dob;
};
void display(struct student[],int);
void insert(struct student[],int);
void delete(struct student[],int);
void search(struct student[],int);
main()
{
int n,i,ch;
struct student stud[10];
printf("\n Enter how many students:");
scanf("%d",&n);
for(i=0;i<n;i++)
http://pradeeppearlz.blogspot.com 22 User-Defined Data types
{
printf("\n Enter student %d details",i+1);
printf("\n Enter roll number:");
scanf("%d",&stud[i].rno);
printf("\n Enter name:");
scanf("%s",stud[i].name);
printf("\n Enter rank:");
scanf("%d",&stud[i].rank);
printf("\n Enter date of birth(day,month,year):");
scanf("%d%d%d",&stud[i].dob.day,&stud[i].dob.month,&stud[i].dob.year);
}
while(1)
{
printf("\n1.Print\n2.Insert\n3.Delete\n4.Search\n5.Exit");
printf("\n Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1: display(stud,n);
break;
case 2: insert(stud,n);
break;
case 3: delete(stud,n);
break;
case 4: search(stud,n);
break;
case 5: exit(0);
default: printf("\n Wrong choice");
}
}
}
void display(struct student s[],int n)
{
int i;
printf("\n Student details");
for(i=0;i<n;i++)
{
printf("\n%d\t%s\t%d\t%d/%d/%d",s[i].rno,s[i].name,s[i].rank,s[i].dob.day,s[i].dob.month,
s[i].dob.year);
}
}
void insert(struct student s[],int n)
{
struct student new;
int pos,i;
printf("\n Enter new student details(rno,name,rank and date of birth):");
scanf("%d%s%d%d%d%d",&new.rno,new.name,&new.rank,&new.dob.day,&new.dob.month,
&new.dob.year);
printf("\n Enter the position:");
scanf("%d",&pos);
for(n++,i=n-1;i>pos-1;i--)
s[i]=s[i-1];
s[pos-1]=new;
display(s,n);
}
void delete(struct student s[],int n)
{
http://pradeeppearlz.blogspot.com 23 User-Defined Data types
int pos,i;
printf("\n Enter the position:");
scanf("%d",&pos);
for(i=pos-1;i<n;i++)
s[i]=s[i+1];
display(s,n);
}
void search(struct student s[],int n)
{
int rollnum,flag=0,pos,i;
printf("\n Enter the roll number to be searched:");
scanf("%d",&rollnum);
for(i=0;i<n;i++)
{
if(s[i].rno==rollnum)
{
pos=i;
flag=1;
break;
}
}
if(flag==1)
{
printf("\n The student details are:");
printf("%d\t%s\t%d\t%d/%d/%d",s[pos].rno,s[pos].name,s[pos].rank,s[pos].dob.day,
s[pos].dob.month,s[pos].dob.year);
}
else
printf("\n The record is not found");
}
2) /* A program to add two matrices using structures*/
#include<stdio.h>
typedef struct
{
int **data;
int row,col;
}matrix;
main()
{
matrix m1,m2,m3;
int i,j;
printf("\n Enter first matrix order:");
scanf("%d%d",&m1.row,&m1.col);
printf("\n Enter second matrix order:");
scanf("%d%d",&m2.row,&m2.col);
if(m1.row!=m2.row||m1.col!=m2.col)
printf("\n Sorry, addition is not possible");
else
{
m1.data=(int **)malloc(m1.row*sizeof(int));
for(i=0;i<m1.row;i++)
m1.data[i]=(int *)malloc(m1.col*sizeof(int));
m3.row=m1.row;
m3.col=m1.col;
m3.data=(int **)malloc(m3.row*sizeof(int));
for(i=0;i<m3.row;i++)
m3.data[i]=(int *)malloc(m3.col*sizeof(int));
12.2.1. Unions
Interview question #8
What is a union?
Union is also a user-defined data type like a structure, except that it provides a way to manipulate
different kinds of data in a single area of storage.
For different situations in a program, some variables may not be relevant, but other variables
are- so a union shares the space instead of wasting storage on variables that are not being used. The
members of a union can be of any data type. The number of bytes used to store a union must be at
least enough to hold the largest member. In most cases, unions contain two or more data types. Only
one member, and thus one data type, can be referenced at a time.
1) Initialization
Though we can initialize all the members of a union at a time, only one member is always active.
Because all the members share the same memory location, the value of one member overwrites
the value of other member that is there in memory. The following program demonstrates this:
#include<stdio.h>
main()
{
union student
{
int rno,age;
char name[15],sex;
float fees;
}s1;
s1.rno=6;
strcpy(s1.name,”Divya”);
s1.age=18;
s1.sex=’f’;
s1.fees=27500.00;
printf(“%d\t%s\t%d\t%c\t%f”,s1.rno,s1.name,s1.age,s1.sex,s1.fees);
}
Output: only the value of fees gets printed properly. All others are garbage values and zeros.
Interview question #9
Can a union be self-referenced?
No, a union can not be self-referenced. How ever, a union can contain a pointer to that union as a
member in it. Hence, the following declaration is perfectly valid:
union list
{
long int data;
union list *next;
};
For the above union type, only 8 bytes of memory will be allocated. These 8 bytes of memory can
be shared by both data and pointer next one after other. Hence, there are chances that the values
of these members can overlap each other which lead to data corruption.
All the members of a structure can be Only first member of union can be initialized.
initialized. e.g., union student stud1 = {46,18,”ravi
kumar”,’m’,27500.00}; is invalid.
e.g., struct student stud1 = {46,18,”ravi
But, union student stud1={46}; is valid.
kumar”,’m’,27500.00};
Any member can be accessed at any time with Since only one member can be handled at a
out loss of data. time, care should be taken to retrieve the data
type from the union variable as the type most
recently used.
Different interpretations for the same memory Different interpretations for the same memory
location are not possible. location are possible.
Once the enumerators are declared in an enumerated data type, each enumerator holds an integer
constant. Usually, these constant start from 0. So, from the above example, it is clear that the
enumerators hold these constants: red=0, green=1, blue=2
#include<stdio.h>
main()
{
enum color{red,green,blue};
printf(“Red=%d\tGreen=%d\tBlue=%d”,red,green,blue);
}
Output: Red=0 Green=1 Blue=2
Note: we can assign enumerators to the variables of enumerated data type and variables of int type also
as follows:
enum day
{sun,mon,tue,wed,thu,fri,sat
} day1,day2;
day1=wed; // day1 holds the value of enumerator-wed. i.e., day1=3
day2=sat; // day2 holds the value of enumerator- sat. i.e., day2=6
int val=wed; // val holds the value of enumerator-wed. i.e., val=3
http://pradeeppearlz.blogspot.com 30 User-Defined Data types
Point to ponder #4
The values of enumerators are fixed; they can never be changed throughout program. When assigned
to a variable, the value in variable can be changed. But that change won’t affect enumerator.
12.4. Bitfields
If a variable in a program takes only one of two values: 0 or 1, we really need a single bit to store it.
Similarly, if a variable is to take values from 0 to 3, then two bits are sufficient to store these values. And
if a variable is to take values from 0 through 7, then three bits will be enough, and so on.
Why do we waste an entire integer (16 bits) when one or two or three bits are sufficient for a variable
to take a value? Well, C provides a concept, i.e., bit field that is used to pack a value in a less number of
bits.