LECTURE 20-21: Structure Types (Chapter 11)
User-defined structure types
Motivation: A database is a collection of information stored in a
computer system. A database is subdivided into records,
which normally contains information regarding specific data objects. Each
record is characterized with a number of attributes.
Structures are appropriate for storing and processing of such data.
In C, a structure can be defined by specifying its components.
For example, a planet can be described by its five attributes:
name, diameter, number of moons, orbit time, and rotation time. To organize
these data together, the following structure type planet_t can be defined:
typedef struct
{
char name[10];
double diameter;
int
moons;
double orbit_time, rotation_time;
} planet_t;
When a variable of structure type is declared, the memory
will be reserved for storing values of its components.
For example,
planet_t current_planet, previous_planet,
blank_planet
= {"", 0, 0, 0, 0};
The last declaration comes
with an initialization of the components,
according to their defining order in the structure.
A component in a structure
type can be a (previously defined) structure type or array, so as to form a
hierarchical structure.
In general, a structure type
is defined in the following format:
typedef struct
{
type_1 name_list_1;
type_2 name_list_2;
... ...
type_n name_list_n;
} type_name;
where a name list consists of components names separated by
comma (",").
A component in a structure
variable can be accessed using the direct component selection operator, which
is a period ("."). A component used in this way is just like a
variable of the corresponding type, as in FIGURE 11.1:

Then, the following statement
printf("%s's equatorial diameter is
%.1f km.\n",
current_planet.name,
current_planet.diameter);
displays the sentence
Jupiter's equatorial diameter is 142800.0 km.
The direct component
selection operator has the highest precedence (when used with other operators)
and is left associative (when occurring more than once). See Table 11.1 (page
556) for a review of precedence and associativity of
operators.
When the name of a structure
type variable is used with no component selection operator, it refers to the
entire structure. A new copy of a structure's
value can be made by an assignment, as the following:
previous_planet = current_planet;
Note that this is very simple,
as compared to arrays or strings.
Structure type data as parameters
When a structured variable is
passed as an input argument to a function, all
of its component values are copied into the components of the function's
corresponding formal parameter. When such a variable is used as an output parameter, the address-of operator must be
used.
For example, see the programs in FIGURE 11.2 and FIGURE 11.4.
/*
* Displays with labels all components of a planet_t structure
*/
void
print_planet(planet_t pl) /* input - one planet
structure */
{
printf("%s\n", pl.name);
printf(" Equatorial
diameter: %.0f km\n", pl.diameter);
printf(" Number of
moons: %d\n", pl.moons);
printf(" Time to
complete one orbit of the sun: %.2f years\n", pl.orbit_time);
printf(" Time to
complete one rotation on axis: %.4f hours\n",
pl.rotation_time);
}
/*
* Fills a type planet_t
structure with input data. Integer returned as
* function result is
success/failure/EOF indicator.
* 1
=> successful input of one planet
* 0
=> error encountered
*
EOF => insufficient data before end of file
* In case of error or EOF, value of type planet_t output argument is
* undefined.
*/
int
scan_planet(planet_t *plnp)
/* output - address of planet_t structure
to
fill */
{
int
result;
result = scanf("%s%lf%d%lf%lf", (*plnp).name,
&(*plnp).diameter,
&(*plnp).moons,
&(*plnp).orbit_time,
&(*plnp).rotation_time);
if (result == 5)
result =
1;
else if (result
!= EOF)
result =
0;
return (result);
}
Please note that in the last
example, &(*plnp).diameter actually means &((*plnp).diameter), and it cannot be further simplified into &*plnp.diameter -- here "."
has higher precedence than "&" and "*", and the other two are right associative.
FIGURE 11.5 shows the data
areas of functions main and scan_planet during
execution of the following statement in main:
status = scan_planet(¤t_planet);

C also provides an indirect
component selection operator, "->", as a
combination of a direct component selection operator and a pointer reference,
that is, when structp
is a pointer to a structure, the following two expressions are equivalent:
(*structp).component // referencing, then direct component
selection
structp->component // indirect component selection
Consequently, the assignment
in FIGURE 11.4 can be rewritten as
result = scanf("%s%lf%d%lf%lf", plnp->name,
&plnp->diameter,
&plnp->moons,
&plnp->orbit_time,
&plnp->rotation_time;
Here "->" has a higher precedence than "&".
Structured return values
In C, a function can return a
structure value, with copies of all its components.
Example (similar to Figure 11.6):
/*
* Gets and returns a planet_t
structure
*/
planet_t scan_planet2(void)
{
planet_t
planet;
scanf("%s%lf%d%lf%lf", planet.name,
&planet.diameter,
&planet.moons,
&planet.orbit_time,
&planet.rotation_time);
return (planet);
}
This function has the same
effect as function scan_planet from Figure 11.4. The
function call would look like:
current_planet = scan_planet2();
Arrays of Structures
For example, if each student record consists of an ID number and
a GPA value, then a list of students can be represented as an array of
structures. Let us define structure student_t first:
typedef
struct {
int id;
double gpa;
} student_t;
To declare an array with 50
student records we can write:
student_t
stulist[50];
and the array is shown in FIGURE 11.11:

The same data can be stored
as two arrays that are "parallel" to each other, in the sense that
the same index indicates data for the same student:
int id_list[50];
double gpa_list[50];
Usually the first way is more
natural and convenient.