Previous: 12.3 Sorting Arrays of Structures
Up: 12 Structures and Unions
Next: 12.5 Common Errors
Previous Page: 12.3 Sorting Arrays of Structures
Next Page: 12.5 Common Errors

12.4 Unions

In some applications, we might want to maintain information of one of two alternate forms. For example, suppose, we wish to store information about a person, and the person may be identified either by name or by an identification number, but never both at the same time. We could define a structure which has both an integer field and a string field; however, it seems wasteful to allocate memory for both fields. (This is particularly important if we are maintaining a very large list of persons, such as payroll information for a large company). In addition, we wish to use the same member name to access identity the information for a person.

C provides a data structure which fits our needs in this case called a union data type. A union type variable can store objects of different types at different times; however, at any given moment it stores an object of only one of the specified types. The declaration of a union type must specify all the possible different types that may be stored in the variable. The form of such a declaration is similar to declaring a structure template. For example, we can declare a union variable, person, with two members, a string and an integer. If the name is entered, we will use person to store the string; if an identification number is entered, we will use person to store an integer. Here is the union declaration:

union {
          int id;
          char name[25];
     } person;
This declaration differs from a structure in that, when memory is allocated for the variable person, only enough memory is allocated to accommodate the largest of the specified types. The memory allocated for person will be large enough to store the larger of an integer or an 25 character array. Like structures, we can define a tag for the union, so the union template may be later referenced by name:
union human {
          int id;
          char name[25];
     } person;
Likewise, it is possible to declare just a tag, and later, use the tag to declare variables:
union human {
          int id;
          char name[25];
     };
     union human person, *ppers;

The syntax for declaring a union type is basically the same as for a structure:

The members of a union variable may be accessed in the same manner as are members of a structure variable: Examples include:

ppers = &person;
     person.id = 12;
     if (ppers->id == 12)
          ...
     printf("Id = %d\n", person.id);
The type of data accessed is determined by the member name used to qualify the variable name. In our example, person.id will access an integer; while person.name will access a string (a character pointer).

Since at any given time, the contents of the union variable may be one of several types ( int or string for person), we must keep track what type of data is stored in order to access the information correctly. Each time an object is stored in a union variable, it is the programmer's responsibility to keep track of the type stored. If an attempt is made to retrieve a type different from the type last stored, the result is sure to be strange and incorrect. The specific behavior is implementation dependent.

To remember the type of object last stored in a union variable, it is common to store that information in a variable. The best way is to declare a structure containing both the union variable as a field and another field that indicates the type of data stored in the union. For example, we can declare such a structure type and a structure array as follows:

#define NAME 0
     #define ID 1
     struct record {
          int ptype;
          union human person;
     };
     struct record list[MAX];
Now, as we read information about each element of list, if the information is numeric, we store it as id; otherwise, we store it as name. We also store the type, ID or NAME in the member, ptype.

Figure 12.15 shows a function that reads identifying information about each person and stores it in the union type member. Depending on the type of information read, it uses the appropriate union field name, and stores the type in the ptype field of the structure.

The loop body in the function looks at the first character of the input string, s. If it is a digit, then the data is an id number so INT is stored in ptype, and the string is converted to an integer (using atoi()) and stored in the union id field. If the first character of s is not a digit, NAME is stored in ptype, and the string is copied into the union name field.

It is now easy to write a function that prints the identifying information stored in the list. Since each record includes the type of information stored in the union variable, it is easy to retrieve the information correctly as shown in Figure 12.16.

We now write a simple program that first reads a list of identifying information about a group of people, and later prints the list. The identifying information may be either a name or an id number. The structure and union declarations as well as constant definitions are included in the file unidef.h shown together with the code in Figure 12.16.

Sample Session:

The above program can be written in many alternate ways. We have written the program to illustrate the use of union variables.



Previous: 12.3 Sorting Arrays of Structures
Up: 12 Structures and Unions
Next: 12.5 Common Errors
Previous Page: 12.3 Sorting Arrays of Structures
Next Page: 12.5 Common Errors

tep@wiliki.eng.hawaii.edu
Sat Sep 3 07:12:43 HST 1994