Arrays provide the facility for grouping related data items of the same type into a single object. However, sometimes we need to group related data items of different types. An example is the inventory record of a stock item that groups together its item number, price, quantity in stock, reorder level etc. In order to handle such situations, C provides a data type, called structures, that allows a fixed number of data items, possibly of different types to be treated as a single object. It is used to group all related information into one variable.
Basics of Structures
Structure is a collection of logically related data items grouped together under a single name, called a structure tag. The data items that make up a structure are called its members or fields, and can be of different types.
The general format for defining a structure is:
struct tag_name { data_type member1; data_type member2; ... };
where,
struct: A keyword that introduces a structure definition.
Tag_name: The name of the structure
member1, member2: Set of type of declarations for the member data items that make up the structure.
For example, the structure for the inventory record of a stock item may be defined as:
struct item { int itemno; float price; float quantity; int reorderlevel; };
Consider another example, of a book database consisting of book name, author, number of pages and price. To hold the book information, the structure can be defined as follows:
struct book_bank { char title[15]; char author[10]; int pages; float price; };
The above declaration does not declare any variables. It simply describes a format called template to represent information as shown below:
struct book_bank title array of 15 characters author array of 10 characters pages integer price float
The following figure illustrates the composition of this book database schematically.
All the members of a structure can be of the same type, as in the following definition of the structure date.
struct date { int day,month,year; };
Declaration of individual members of a structure
The individual members of a structure may be any of the data types (such as int, float, etc.), pointers, arrays or even other structures. The individual members of a structure may be any of the data types (such as int, float, etc.), pointers, arrays or even other structures.
Individual members cannot be initialized inside the structure declaration.
Structure variables
A structure definition defines a new type, and variables of this type can be declared in the following ways:
In the structure declaration: By including a list of variable names between the right brace and the termination semicolon in the structure definition.
For example, the declaration:
struct student { int rollno; char subject[10]; float marks; } student1, student2;
declares student1, student2 to be variables of type struct student. If other variables of the structure are not required, the tag name student can be omitted as shown below:
struct { int rollno; char name[10]; float marks; } student1, student2;
Using the structure tag
The structure tag can be thought of as the name of the type introduced by the structure definition and variables can also be declared to be of a particular structure type by a declaration of the form:
struct tag variable-list;
For example,
struct student student1,student2;
declares student1 and student2 to be variables of type struct student.
Structure Initilization
A variable of particular structure type can be initialized by following its definition with an initializer for the corresponding structure type. Initializer contains initial values for components of the structure, placed within curly braces and separated by commas. Thus, the declaration:
struct date { int day,month,year; }independence={15,8,1947};
initializes the member variables day, month and year of the structure variable independence to 15, 8 and 1947 respectively.
The declaration:
struct date republic ={26,1,1950};
initializes the member variables day, month and year of the structure variable republic to 26, 1 and 1950 respectively. Considering the structure definition student (defined in 8.1.2), the declaration
struct student student1={1,”Ashwini”,98.5};
Initializes the member variables rollno, name and marks of the structure variable student1 to 1, “Ashwini” and 98.5 respectively. If there are fewer initializers than that of member variables in the structure, the remaining member variables are initialized to zero.
Thus the initialization:
struct date newyear={1,1};
is same as:
struct date newyear={1,1,0};
Accessing structure members
With the help of dot operator(.), individual elements of a structure can be accessed and the syntax is of the form:
structure-variable.member-name;
Thus to refer to name of the structure student, we can use:
student1.name;
The statements,
struct date emp; emp.day=28; emp.month=7; emp.year=1969;
set the values of the member variables day, month and year within the variable emp to 28, 7 and 1969 respectively and the statement.
struct date today; if(today.day==1&&today.month==1) printf(“Happy New Year”);
tests the values of day and month to check if both are 1 and if so, prints the message. The elements of a structure are always stored in contiguous memory locations. It is shown below:
Following are some example given using structures:
/* Program to print the date using structure variable */ # include<stdio.h> void main(void) { struct date { char month[15]; int day,year; }; struct date today; today.day=11; printf(“Enter Month : ”); scanf(“%[^\n]”,today.month); today.year=1998; printf(“\nToday’s date is %d-%s-%d \n”, today.day,today.month,today.year); }
*** str.h *** struct date { int month,day,year; };
/* Program to print the date using structure variable */ #include<stdio.h> # include “str.h” void main(void) { struct date today; struct date tomorrow; static int day_month[12]= {31,28,31,30,31,30,31,31,30,31,30,31}; printf(“Enter Today’s date (dd:mm:yy): ”); scanf(“%d%d%d”,&today.day,&today.month,&today.year); if(today.day > day_month[today.month-1]) { printf(“\n Invalid Date \n”); exit(0); } if(today.day!=day_month[today.month-1]) { tomorrow.day=today.day+1; tomorrow.month=today.month; tomorrow.year=today.year; } else if(today.month==12) { tomorrow.day=1; tomorrow.month=1; tomorrow.year=today.year+1; } else { tomorrow.day=1; tomorrow.month= today.month+1; tomorrow.year=today.year; } printf(“\n Tomorrow’s date is %d-%d-%d \n”, tomorrow.day,tomorrow.month,tomorrow.year); }
One structure can be copied to another structure of same type directly using the assignment operator as well as element by element basis like arrays.
In this case, the values of members of a structure variable get assigned to members of another structure variable of the same type. It is illustrated in the following example.
*** strdef.h *** struct date { char month[5]; int day,year; };
/* Example - To copy a structure to another structure */ # include <stdio.h> # include <string.h> # include "strdef.h" void main(void) { struct date today={“March”,1,98}; struct date day1,day2; /* copying element by element basis */ strcpy(day1.month,today.month); day1.day=today.day; day1.year=today.year; /* copying entire structure to another structure */ day2=day1; printf(“\n Date is %d %s %d \n”, today.day,today.month,today.year); printf(“\nDate is %d %s %d \n”, day1.day,day1.month,day1.year); printf(“\n Date is %d %s %d \n”, day2.day,day2.month,day2.year); }
Functions and Structures
We can pass structures as arguments to functions. Unlike array names however, which always point to the start of the array, structure names are not pointers. As a result, when we change structure parameter inside a function, we don’t effect its corresponding argument.
Passing structure to elements to functions:
A structure may be passed into a function as individual member or a separate variable. A program example to display the contents of a structure passing the individual elements to a function is shown below.
# include < stdio.h > void main() { int emp_id; char name[25]; char department[10]; float salary; }; static struct emp1={125,”sampath”,”operator”,7500.00}; /* pass only emp_id and name to display function*/ display(emp1.emp_id,emp1.name); } /* function to display structure variables*/ display(int e_no,char *e_name) { printf(“%d%s”,e_no,e_name); }
In the declaration of structure type, emp_id and name have been declared as integer and character array. When we call the function display() using display(emp1.emp_id,emp1.name); we are sending the emp_id and name to function display(). It can be immediately realized that to pass individual elements would become more tedious as the number of structure elements go on increasing a better way would be to pass the entire structure variable at a time.
Passing entire structure to functions:
In case of structures having to having numerous structure elements passing these individual elements would be a tedious task. In such cases we may pass whole structure to a function as shown below:
# include <stdio.h> { int emp_id; char name[25]; char department[10]; float salary; }; void main() { static struct employee emp1= {12, “sadanand”, “computer”, 7500.00}; display(emp1); /*sending entire employee structure*/ } /*function to pass entire structure variable*/ display(struct employee empf) { printf(“%d%s,%s,%f”, empf.empid,empf.name,empf.department,empf.salary); }
Structures and Arrays
Arrays and structures can be freely intermixed to create arrays of structures, structures containing arrays.
Arrays of Structures
In the array of structures array contains individual structures as its elements. These are commonly used when a large number of similar records are required to be processed together.
For example, the data of motor containing 1000 parts can be organized in an array of structure as
struct item motor[1000];
This statement declares motor to be an array containing 1000 elements of the type struct item.
An array of structures can be declared in two ways as illustrated below. The first way is by declaring:
struct person { char name[10]; struct date birthday; float salary; }emprec[15];
In this case, emprec is an array of 15 person structures. Each element of the array emprec will contain the structure of type person. The person structure consists of 3 individual members : an array name, salary and another structure date. The embedded structure date must be declared before its use within the containing structure. The second approach to the same problem involves the use of the structure tag as below.
struct person { char name[10]; struct date birthday; float salary; }; struct person emprec[15];
Following program explains how to use an array of structures.
/* Example- An array of structures */ # include<stdio.h> void main(void) { struct book { char name[15]; int pages; float price; }; struct book b[10]; int i; printf(“\n Enter name, pages and price of the book\n”); /* accessing elements of array of structures */ for(i=0;i<9;i++) { scanf(“%s%d%f”,b[i].name,&b[i].pages,&b[i].price); printf(“\n”); } printf(“\n Name, Pages and Price of the book :\n”); for(i=0;i<=9;i++) { printf(“%s %d %f”,b[i].name,b[i].pages,b[i].price); } }
Arrays within Structures
A structure may contain arrays as members. This feature is frequently used when a string needs to be included in a structure. For example, the structure date can be expanded to also include the names of the day of the week and month as:
struct date { char weekday[10]; int day; int month; char monthname[10]; int year; };
A structure variable ndate can be declared and initialized as –
struct date ndate={”Sunday”,21,11,”November”,2004};
An element of an array contained in a structure can be accessed using the dot and array subscript operators. Thus the statement,
printf(“%c”,ndate.monthname[2]);
prints v.
Structures and Pointers
Pointers to Structures
The beginning address of a structure can be accessed in the same manner as any other address, through the use of the address of (&) operator. Thus, if variable represents a structure-type variable, then:
&variable
represents the starting address of that variable. Moreover, we can declare a pointer variable for a structure by writing:
type *ptvar;
where,
type: A data type that identifies the composition of the structure
ptvar: The name of the pointer variable
Pointer variable holding address of structure is called Structure Pointers. For example, the declaration:
struct date ndate,*ptrndate;
declares ndate to be a variable of type struct date and the variable ptrndate to be a pointer to a struct date variable. Consider the following example:
typedef struct { int acct_no; char acct_type; char name[20]; float balance; date lastpayment; }account; account customer,*pc;
In this example, customer is a structure variable of type account, and pc is a pointer variable whose object is a structure of type account. The address operator (&) is applied to a structure variable to obtain the beginning address of customer. It can be assigned to pc by writing.
pc=&customer;
The variable and pointer declarations can be combined with the structure declaration by writing
struct { member 1; member 2; ... member n; }variable,*ptvar;
Where,
variable: A structure type variable
ptvar: The name of a pointer variable
The following single declaration is equivalent to the two declarations presented in the previous example.
struct { int acct_no; char acct_type; char name[20]; float balance; date lastpayment; }customer,*pc;
The pointer variable pc can now be used to access the member variables of customer using the dot operator as:
(*pc).acct_no; (*pc).acct_type; (*pc).name;
The parentheses are necessary because the dot operator(.) has higher precedence than that of the dereferencing operator(*). The members can also be accessed by using a special operator called the structure pointer or arrow operator (->).
The general form for the use of the operator -> is
printer_name->member_name;
Thus,
if pc=&customer pc->balance=(*pc).balance=customer.balance
where, balance is member of structure customer.
It is possible to take addresses of the member variables of a structure variable. For example, the statement
float *ptrbal=&customer.balance;
defines ptrbal to be a floating point pointer and initializes it to point to the member variable balance within the structure variable customer. The pointer expression &customer.balance is interpreted as &(customer.balance) since, the precedence of the dot operator is higher than that of the address operator.
/* Example- structure pointers */ # include <stdio.h> # include "str.h" struct { int acct_no; char acct_type; char *name; float balance; struct date *lastpayment; }customer, *pc = &customer; struct date PaymentDate ; void main(void) { PaymentDate.day = 26 ; PaymentDate.month = 1 ; PaymentDate.year = 1999 ; customer.acct_no=55; customer.acct_type='A'; customer.name="Ashwini"; customer.balance=99.99; customer.lastpayment = &PaymentDate ; printf("Account:%d\n",pc->acct_no); printf("Acc_Type : %c \n",pc->acct_type); printf("Name : %s \n",pc->name); printf("Balance : %.2f \n",pc->balance); printf("LastPayment : %2d-%2d-%4d \n", pc->lastpayment->day,pc->lastpayment->month, pc->lastpayment->year); }
Within the second structure, the members acct_no, acct_type, name and balance are written as pointers. Thus, the value to which acct_no points can be accessed by writing either *customer.acct_no or *p->acct_no. Same in case of acct_type and balance. A string can be assigned directly to a character type pointer. Therefore, if name points to the beginning of a string, then the string can be accessed by writing either customer.name or pc->name.
Allocating Memory for Pointer to a Structure
Memory from the heap is to be allocated for a pointer to a structure if you want to store some data, this is done by using malloc() function.
Example:
typedef struct { char name[20]; char address[20]; int empid; }emp,*empptr;
The memory to store information about 10 employees can be allocated by the statement:
empptr=(emp*)malloc(10*sizeof(emp));
After the memory is allocated you can use the pointer to get the information as follows
for(i=0;i<10;i++) { scanf(“%s%s%d”,empptr[i].name,empptr[i].address, & empptr[i].empid); }
Structures Containing Pointers
A structure can contain pointers as member variables. For example, the structure definition,
struct location { char *name; char *addr; };
defines a structure location that contains two character pointers, name and addr as member variables. Variables of type struct location can now be defined and manipulated as in:
struct location att={“Ashwini”,”Boston’s Computer Institute”}; struct location ibm; ibm.name=”R&D”; ibm.addr=”Bell Labs,California”;
accessing structure date defined in str.h:
*** str1.h *** # include “str.h” struct person { char name[20]; char *lastname; struct date birthday; float *salary; }emprec;
*** strptr.c***:
/* Example- structure containing pointers */ # include<stdio.h> # include “str1.h” void main(void) { float x; struct person *ptr = &emprec; struct date *birth = &emprec.birthday; strcpy(emprec.name,”Ashwini”); emprec.lastname = ”A.”; ptr->birthday.day = 28; emprec.birthday.month = 7; birth->year = 97; x=5000; ptr->salary = &x; printf(“ *** Employee Details *** \n”); printf(“Name :%s %s \n”,ptr->name,ptr->lastname); printf(“Birthdate: %d:%d:%d \n”,(*ptr).birthday.day, birth->month,emprec.birthday.year); printf(“Salary :%6.2f”,emprec.salary); }
Output:
*** Employee Details *** Name: Ashwini A. Birthday: 28:7:97 Salary: 5000.00
Allocating Memory for Structure containing Pointer
When there is member of a structure, which is pointer to a structure, it is not enough to allocate memory for the pointer to the structure but you have to allocate memory for member pointer too.
Example: typedef struct { char* name; char* address; int empid; }emp,*empptr;
Following program illustrates memory allocation of pointer within structure. The program allows the user to enter total number of employees and size of name at runtime.
#include <stdio.h> #include <alloc.h> #include <string.h> void main(void) { int n,i,j; typedef struct { int empno; char *name; }emp; emp *empptr; char name[80] ; printf("Enter total no. of employees:"); scanf("%d",&n); fflush(stdin); empptr = (emp *) malloc(n * sizeof(emp)); for(i = 0 ; i < n ; i++) { printf("\n Enter empno of employee (%d) :",i+1); scanf("%d",&empptr[i].empno); fflush(stdin); printf("\n Enter name :"); scanf("%[^\n]",name); fflush(stdin); empptr[i].name = (char *) malloc(strlen(name) * sizeof(char) + 1 ); strcpy(empptr[i].name, name) ; } for(i=0;i < n ; i++) { printf("\nno-%d \tname-%s",empptr[i].empno, empptr[i].name); } }