Lesson-12 Structure and Union

12.1 Introduction

Which mechanic is good enough who knows how to repair only one type of vehicle? None. Same thing is true about C language. It wouldn’t have been so popular had it been able to handle only all ints, or all floats or all chars at a time. In fact when we handle real world data, we don’t usually deal with little atoms of information by themselves—things like integers, characters and such. Instead we deal with entities that are collections of things, each thing having its own attributes, just as the entity we call a ‘book’ is a collection of things such as title, author, call number, publisher, number of pages, date of publication, etc. As you can see all this data is dissimilar, for example author is a string, whereas number of pages is an integer. For dealing with such collections, C provides a data type called ‘structure’. A structure gathers together, different atoms of information that comprise a given entity. And structure is the topic of this chapter.

12.2 Why Structure?

We have seen earlier how ordinary variables can hold one piece of information and how arrays can hold a number of pieces of information of the same data type. These two data types can handle a great variety of situations. But quite often we deal with entities that are collection of dissimilar data types.

For example, suppose you want to store data about a book. You might want to store its name (a string), its price (a float) and number of pages in it (an int). If data about say 3 such books is to be stored, then we can follow two approaches:

  • Construct individual arrays, one for storing names, another for storing prices and still another for storing number of pages.

  • Use a structure variable.

Let us examine these two approaches one by one. For the sake of programming convenience assume that the names of books would be single character long. Let us begin with a program that uses arrays.

#include<stdio.h>

void main()

{

char name[3] ;

float price[3] ;

int pages[3], i ;

printf ( "\nEnter names, prices and no. of pages of 3 books\n" ) ;

for ( i = 0 ; i <= 2 ; i++ )

scanf ( "%c %f %d", &name[i], &price[i], &pages[i] );

printf ( "\nAnd this is what you entered\n" ) ;

for ( i = 0 ; i <= 2 ; i++ )

printf ( "%c %f %d\n", name[i], price[i], pages[i] );

}

And here is the sample run...

Enter names, prices and no. of pages of 3 books

A 100.00 354

C 256.50 682

F 233.70 512

And this is what you entered

A 100.000000 354

C 256.500000 682

F 233.700000 512

This approach no doubt allows you to store names, prices and number of pages. But as you must have realized, it is an unwieldy approach that obscures the fact that you are dealing with a group of characteristics related to a single entity—the book.

The program becomes more difficult to handle as the number of items relating to the book go on increasing. For example, we would be required to use a number of arrays, if we also decide to store name of the publisher, date of purchase of book, etc. To solve this problem, C provides a special data type—the structure.

A structure contains a number of data types grouped together. These data types may or may not be of the same type. The following example illustrates the use of this data type.

#include<stdio.h>

void main()

{

            struct book

            {

                        char name ;

float price ;

int pages ;

            };

            struct book b1,b2,b3;

printf ( "\nEnter names, prices & no. of pages of 3 books\n" ) ;

scanf ( "%c %f %d", &b1.name, &b1.price, &b1.pages ) ;

scanf ( "%c %f %d", &b2.name, &b2.price, &b2.pages ) ;

scanf ( "%c %f %d", &b3.name, &b3.price, &b3.pages ) ;

printf ( "\nAnd this is what you entered" ) ;

printf ( "\n%c %f %d", b1.name, b1.price, b1.pages ) ;

printf ( "\n%c %f %d", b2.name, b2.price, b2.pages ) ;

printf ( "\n%c %f %d", b3.name, b3.price, b3.pages ) ;

}

And here is the output...

Enter names, prices and no. of pages of 3 books

A 100.00 354

C 256.50 682

F 233.70 512

A 100.000000 354

C 256.500000 682

F 233.700000 512

This program demonstrates two fundamental aspects of structures:

  • declaration of a structure

  • accessing of structure elements

Let us now look at these concepts one by one.

12.3 Declaring a Structure

In our example program, the following statement declares the structure type:

struct book

{

char name ;

float price ;

int pages ;

} ;

This statement defines a new data type called struct book. Each variable of this data type will consist of a character variable called name, a float variable called price and an integer variable called pages. The general form of a structure declaration statement is given below:

struct <structure name>

{

structure element 1 ;

structure element 2 ;

structure element 3 ;

......

......

} ;

Once the new structure data type has been defined one or more variables can be declared to be of that type. For example the variables b1, b2, b3 can be declared to be of the type struct book, as,

struct book b1, b2, b3 ;

This statement sets aside space in memory. It makes available space to hold all the elements in the structure—in this case, 7 bytes—one for name, four for price and two for pages. These bytes are always in adjacent memory locations.

If we so desire, we can combine the declaration of the structure type and the structure variables in one statement.

For example,

struct book

{

char name ;

float price ;

int pages ;

} ;

struct book b1, b2, b3 ;

is same as...

struct book

{

char name ;

float price ;

int pages ;

} b1, b2, b3 ;

or even...

struct

{

char name ;

float price ;

int pages ;

} b1, b2, b3 ;

Like primary variables and arrays, structure variables can also be initialized where they are declared. The format used is quite similar to that used to initiate arrays.

struct book

{

char name[10] ;

float price ;

int pages ;

} ;

struct book b1 = { "Basic", 130.00, 550 } ;

struct book b2 = { "Physics", 150.80, 800 } ;

Note the following points while declaring a structure type:

  • The closing brace in the structure type declaration must be followed by a semicolon.

  • It is important to understand that a structure type declaration does not tell the compiler to reserve any space in memory. All a structure declaration does is, it defines the ‘form’ of the structure.

  • Usually structure type declaration appears at the top of the source code file, before any variables or functions are defined. In very large programs they are usually put in a separate header file, and the file is included (using the preprocessor directive #include) in whichever program we want to use this structure type.

12.4 Accessing Structure Elements

Having declared the structure type and the structure variables, let us see how the elements of the structure can be accessed.

In arrays we can access individual elements of an array using a subscript. Structures use a different scheme. They use a dot (.) operator. So to refer to pages of the structure defined in our sample program we have to use,

b1.pages

Similarly, to refer to price we would use,

b1.price

Note that before the dot there must always be a structure variable and after the dot there must always be a structure element.

12.5 How Structure Elements are Stored

Whatever be the elements of a structure, they are always stored in contiguous memory locations. The following program would illustrate this:

/* Memory map of structure elements */

void main( )

{

struct book

{

char name ;

float price ;

int pages ;

} ;

struct book b1 = { 'B', 130.00, 550 } ;

printf ( "\nAddress of name = %u", &b1.name ) ;

printf ( "\nAddress of price = %u", &b1.price ) ;

printf ( "\nAddress of pages = %u", &b1.pages ) ;

}

Here is the output of the program...

Address of name = 65518

Address of price = 65519

Address of pages = 65523

Actually the structure elements are stored in memory as shown in the Figure

fig-12.1

12.6 Array of Structures

Our sample program showing usage of structure is rather simple minded. All it does is, it receives values into various structure elements and output these values. But that’s all we intended to do anyway... show how structure types are created, how structure variables are declared and how individual elements of a structure variable are referenced.

In our sample program, to store data of 100 books we would be required to use 100 different structure variables from b1 to b100, which is definitely not very convenient. A better approach would be to use an array of structures. Following program shows how to use an array of structures.

/* Usage of an array of structures */

void main( )

{

struct book

{

char name ;

float price ;

int pages ;

} ;

struct book b[100] ;

int i ;

for ( i = 0 ; i <= 99 ; i++ )

{

printf ( "\nEnter name, price and pages " ) ;

scanf ( "%c %f %d", &b[i].name, &b[i].price, &b[i].pages ) ;

}

for ( i = 0 ; i <= 99 ; i++ )

printf ( "\n%c %f %d", b[i].name, b[i].price, b[i].pages ) ;

}

linkfloat( )

{

float a = 0, *b ;

b = &a ; /* cause emulator to be linked */

a = *b ; /* suppress the warning - variable not used */

}

Now a few comments about the program:

  • Notice how the array of structures is declared...

struct book b[100] ;

This provides space in memory for 100 structures of the type struct book.

      • The syntax we use to reference each element of the array b is similar to the syntax used for arrays of ints and chars. For example, we refer to zeroth book’s price as b[0].price. Similarly, we refer first book’s pages as b[1].pages.

      • It should be appreciated what careful thought Dennis Ritchie has put into C language. He first defined array as a collection of similar elements; then realized that dissimilar data types that are often found in real life cannot be handled using arrays, therefore created a new data type called structure. But even using structures programming convenience could not be achieved, because a lot of variables (b1 to b100 for storing data about hundred books) needed to be handled. Therefore he allowed us to create an array of structures; an array of similar data types which themselves are a collection of dissimilar data types. Hats off to the genius!

      • In an array of structures all elements of the array are stored in adjacent memory locations. Since each element of this array is a structure, and since all structure elements are always stored in adjacent locations you can very well visualise the arrangement of array of structures in memory. In our example, b[0]’s name, price and pages in memory would be immediately followed by b[1]’s name, price and pages, and so on.

  • What is the function linkfloat( ) doing here? If you don’t define it you are bound to get the error "Floating Point Formats Not Linked" with majority of C Compilers. What causes this error to occur? When parsing our source file, if the compiler encounters a reference to the address of a float, it sets a flag to have the linker link in the floating-point emulator. A floating point emulator is used to manipulate floating point numbers in runtime library functions like

  • scanf( ) and atof( ). There are some cases in which the reference to the float is a bit obscure and the compiler does not detect the need for the emulator. The most common is using scanf( ) to read a float in an array of structures as shown in our program. How can we force the formats to be linked? That’s where the linkfloat( ) function comes in. It forces linking of the floating-point emulator into an application. There is no need

12.6 Additional Features of Structures

Let us now explore the intricacies of structures with a view of programming convenience. We would highlight these intricacies with suitable examples:

12.6.1 Assigning Structure Variable

The values of a structure variable can be assigned to another structure variable of the same type using the assignment operator. It is not necessary to copy the structure elements piece-meal. Obviously, programmers prefer assignment to piece-meal copying. This is shown in the following example.

void main( )

{

struct employee

{

char name[10] ;

int age ;

float salary ;

} ;

struct employee e1 = { "Sanjay", 30, 5500.50 } ;

struct employee e2, e3 ;

/* piece-meal copying */

strcpy ( e2.name, e1.name ) ;

e2.age = e1.age ;

 

e2.salary = e1.salary ;

/* copying all elements at one go */

e3 = e2 ;

printf ( "\n%s %d %f", e1.name, e1.age, e1.salary ) ;

printf ( "\n%s %d %f", e2.name, e2.age, e2.salary ) ;

printf ( "\n%s %d %f", e3.name, e3.age, e3.salary ) ;

}

The output of the program would be...

Sanjay 30 5500.500000

Sanjay 30 5500.500000

Sanjay 30 5500.500000

Ability to copy the contents of all structure elements of one variable into the corresponding elements of another structure variable is rather surprising, since C does not allow assigning the contents of one array to another just by equating the two. As we saw earlier, for copying arrays we have to copy the contents of the array element by element.

This copying of all structure elements at one go has been possible only because the structure elements are stored in contiguous memory locations. Had this not been so, we would have been required to copy structure variables element by element. And who knows, had this been so, structures would not have become popular at all.

12.6.2 Nesting of Structure

One structure can be nested within another structure. Using this facility complex data types can be created. The following program shows nested structures at work.

main( )

{

struct address

{

char phone[15] ;

char city[25] ;

int pin ;

} ;

struct emp

{

char name[25] ;

struct address a ;

} ;

struct emp e = { "jeru", "531046", "nagpur", 10 };

printf ( "\nname = %s phone = %s", e.name, e.a.phone ) ;

printf ( "\ncity = %s pin = %d", e.a.city, e.a.pin ) ;

}

And here is the output...

name = jeru phone = 531046

city = nagpur pin = 10

Notice the method used to access the element of a structure that is part of another structure. For this the dot operator is used twice, as in the expression,

e.a.pin or e.a.city

Of course, the nesting process need not stop at this level. We can nest a structure within a structure, within another structure, which is in still another structure and so on... till the time we can comprehend the structure ourselves. Such construction however gives rise to variable names that can be surprisingly self descriptive, for example:

maruti.engine.bolt.large.qty

This clearly signifies that we are referring to the quantity of large sized bolts that fit on an engine of a maruti car.

12.6.3 Pointer to Structure

The way we can have a pointer pointing to an int, or a pointer pointing to a char, similarly we can have a pointer pointing to a struct. Such pointers are known as ‘structure pointers’. Let us look at a program that demonstrates the usage of a structure pointer.

void main( )

{

struct book

{

char name[25] ;

char author[25] ;

int callno ;

} ;

struct book b1 = { "Agricultural Engineering", "YRD", 101 } ;

struct book *ptr ;

ptr = &b1 ;

printf ( "\n%s %s %d", b1.name, b1.author, b1.callno ) ;

printf ( "\n%s %s %d", ptr->name, ptr->author, ptr->callno ) ;

}

The first printf( ) is as usual. The second printf( ) however is peculiar. We can’t use ptr.name or ptr.callno because ptr is not a structure variable but a pointer to a structure, and the dot operator requires a structure variable on its left. In such cases C provides an operator  ->, called an arrow operator to refer to the structure elements. Remember that on the left hand side of the ‘.’ structure operator, there must always be a structure variable, whereas on the left hand side of the ‘->’ operator there must always be a pointer to a structure. The arrangement of the structure variable an

fig-12.3

Can we not pass the address of a structure variable to a function? We can. The following program demonstrates this.

/* Passing address of a structure variable */

struct book

{

char name[25] ;

char author[25] ;

int callno ;

} ;

main( )

{

struct book b1 = { "Let us C", "YPK", 101 } ;

display ( &b1 ) ;

}

display ( struct book *b )

{

printf ( "\n%s %s %d", b->name, b->author, b->callno ) ;

}

And here is the output...

Agricultural Engineering YRD 101

Again note that to access the structure elements using pointer to a structure we have to use the ‘->’ operator.

Also, the structure struct book should be declared outside main( ) such that this data type is available to display( ) while declaring pointer to the structure.

12.6 Union

Union is user defined data type used to stored data under unique variable name at single memory location.

Union is similar to that of stucture. Syntax of union is similar to stucture. But the major difference between structure and union is 'storage.' In structures, each member has its own storage location, whereas all the members of union use the same location. Union contains many members of different types, it can handle only one member at a time.

To declare union data type, 'union' keyword is used.

Union holds value for one data type which requires larger storage among their members.

Syntax:

            union union_name

            {

                        <data-type> element 1;

                        <data-type> element 2;

                        <data-type> element 3;

            }union_variable;

Example:

            union techno

            {

                        int comp_id;

                        char nm;

                        float sal;

            }tch;

In above example, it declares tch variable of type union. The union contains three members as data type of int, char, float. We can use only one of them at a time.

fig-12.4

To access union members, we can use the following syntax.

#include <stdio.h>

#include <conio.h>

union techno

{

            int id;

            char nm[50];

}tch;

void main()

{

            clrscr();

            printf("\n\ Enter developer id : ");

            scanf("%d", &tch.id);

            printf("\n Enter developer name : ");

            scanf("%s", tch.nm);

            printf("\n Developer ID : %d", tch.id);//Garbage

            printf("\n\ Developed By : %s", tch.nm);

            getch();

}

And the output is…..

Enter developer id : 101

Enter developer name :Pankaj

Developer id : 25658

Developer name :Pankaj

Last modified: Monday, 28 October 2013, 7:00 AM