Previous: 12.1.3 Structures and Functions
Up: 12.1 Structures
Previous Page: 12.1.3 Structures and Functions
Next Page: 12.2 Arrays of Structures
As we saw in the last section, passing and returning structures to functions may not be efficient, particularly if the structure is large. We can eliminate this excessive data movement by passing pointers to the structures to the function, and access them indirectly through the pointers. Figure 12.4 shows a modified version of our previous program which uses pointers instead of passing entire structures.
The code is very similar to Figure 12.3, but we have changed the prototypes and functions to work with pointers. The argument of read_part() is a pointer to the inventory structure, item declared in main(). The function accesses the object pointed to by partptr, and uses the dot operator to access a member of that object. Since partptr points to an object of type struct inventory, we dereference the pointer to access the members of the object:
(*partptr).part_no (*partptr).cost (*partptr).priceSimilar changes have been made to print_part(). Note, the parentheses are necessary here because the . operator has higher precedence than the indirection operator, *. We must first dereference the pointer, and then select its appropriate member.
Since, for efficiency, pointers to structures are often passed to functions, and, within those functions, the members of the structures are accessed, the operation of dereferencing a structure pointer and a selecting a member is very common in programs. Therefore, C provides a special pointer operator, , (called arrow) to access a member of a structure pointed to by a pointer variable. The operator is a minus symbol, -, followed by a greater-than symbol, >. This operator is exactly equivalent to a dereference operation followed by the . operator as shown below:
The left hand expressions are equivalent ways of writing expressions on the right hand side, e.g. prtptr member accesses the member of an object pointed to by partptr. Our code for read_part() could use the following alternative expressions:
partptr->part_no = n; partptr->cost = x; partptr->price = x;The general syntax for using the arrow operator is:
We now consider an example using nested structures. The program reads and prints data for a single label consisting of members that are themselves structures. The first member is a structure for a name, the second is a structure for an address. This program is organized in several source and header files as shown in Figure 12.5. (We intend to use the functions in these files for other programs as well).
The driver calls the function readlabel() to read in the label data, and the function printlabel() to print the label data. Like the previous example, in both function calls, we assume that a pointer to a struct label variable is passed as an argument. In the functions, we will use the pointer operator, , to access the members of the object pointed to by the pointer. The function prototypes are shown in the header file lblutil.h. The functions are shown in Figure 12.6
The formal parameter in the functions readlabel() and printlabel() are both a pointer, called pptr, which points to an object of type struct label. Each function accesses the first field of the name field of the object pointed to by pptr as follows:
pptr->name.firstRemember, this is the same as:
(*pptr).name.firstwhich means pptr is first dereferenced; the name field of the dereferenced object is accessed next, and finally the first field of name is accessed (the dot operator groups from left to right). Similarly, other members of the object pointed to by pptr are accessed by:
pptr->name.middle pptr->name.last pptr->address.street pptr->address.city pptr->address.state pptr->address.zip
All the above members, except zip, are strings. In readlabel(), scanf() expects to be passed pointers to objects to store the data read. Since all the string members are already pointers, we need to use the address operator only when we pass the pointer to pptr->address.zip. Notice, we use the suppression conversion, %*c, to discard the newline character at the end of each line. Thus, after the name is read, gets() reads the street address correctly. The function returns TRUE if a label is read successfully, and FALSE otherwise, i.e. when an EOF is entered by the user for the name, indicating that no label data is available. The function printlabel() could have been passed the structure variable itself since it merely needs to print the values of the members; however, as we discussed above, passing a pointer avoids the expense of copying the entire structure. Here is a sample session: