LECTURE 23-24: 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.