Structures
1
User-Defined Types
• C provides facilities to define one’s own types.
• These may be a composite of basic types (int, double,
etc) and other user-defined types.
• The most common user-defined type is a structure,
defined by the keyword struct.
• Another, less common, form of user-defined type is a
union, which we will not cover in detail in this course.
2
Structures
• A structure is a collection of one or more variables, possibly of
different types, grouped together under a single name for
convenient handling (K&R page 127).
• Structures are user-defined aggregate types.
• They assist program organisation by
– Grouping logically related data, and giving this set of variables a higher-level
name and more abstract representation.
– Enabling related variables to be manipulated as a single unit rather than as
separate entities.
– Reducing the number of parameters that need to be passed between
functions.
– Providing another means to return multiple values from a function.
3
Structure Syntax
• A structure is defined by the keyword struct followed by a set of variables
enclosed in braces.
• Consider the following structure to represent a person’s details.
struct Personnel {
char name[100];
int age;
double height;
};
• The variables name, age and height are called members of the structure type
Personnel.
• Style note: Structures are given names with Capital first letters, by convention.
Distinguish them from variables and functions (lowercase first letter), and
symbolic constants (all uppercase).
4
Declaring Structure Variables
• There are two ways to define variables of a particular structure
type.
1. Declare them at the structure definition.
struct Personnel {
char name[100];
int age;
double height;
} p1, p2, p3; /* Define 3 variables */
2. Define the variables at some point after the structure definition.
struct Personnel p1, p2, p3; /* Define 3 variables */
5
Initialising Structure Variables
• A structure may be initialised when it is defined using
brace notation.
struct Personnel captain = {“Fred”, 37, 1.83};
• The order of values in the initialiser list matches the
order of declarations in the structure.
6
Accessing Members
• Members of a structure type may be accessed via the “.”
member operator.
struct Personnel captain;
strcpy(captain.name, “Fred”);
captain.age = 37;
captain.height = 1.83;
printf(“%s is %d years old.”,
captain.name, captain.age);
7
Nested Structures
• Structures may be defined inside other structures.
struct Payroll {
struct Personnel person;
double amount;
};
• To access lower-level members, need to use member
operator multiple times.
struct Payroll lieutenant;
lieutenant.person.height = 2.1;
lieutenant.amount = 75.4;
8
Operations on Structures
• Structure types only support one of the operations that are permitted on
primitive types.
– Assignment (ie., copying) is permitted
– All other operations (ie., arithmetic, relational, logical) are not allowed
struct Personnel p1 = {“Fred”, 37, 1.83};
struct Personnel p2;
p2 = p1; /* Valid. */
if (p1 == p2) /* Invalid. Won’t compile. */
printf(“People are equal\n");
if (strcmp(p1.name, p2.name) == 0 && /* Valid. */
p1.age == p2.age &&
p1.height == p2.height)
printf("People are equal\n");
9
Aside: “Fast” Array Copy
• It is not possible to copy arrays directly
int x[5] = { 1, 2, 3, 4, 5 };
int y[5];
y = x /* Invalid, won’t compile */
• But you can achieve direct copy using a struct
– See arraycopy.c
10
Structures and Functions
• Structures may be passed to functions and returned from
functions.
– Like all variables, they are passed by value
– This is a consequence of being copyable
– See details.c
• This can potentially be extremely dangerous
– Structures can be v. large, containing arrays with thousands of
elements
– Copy can take LOTS of time.
11
Pointers to Structures
• Defining pointers is the same as for variables of primitive types
struct Personnel captain = {“Fred”, 37, 1.83};
struct Personnel *pp;
pp = &captain;
(*pp).age = 38; /* captain.age is now 38. */
• Notice the parentheses around the dereferenced pointer.
– This is necessary to enforce correct precedence
– Ugly notation
12
Pointer to Member Operator ->
• An alternative notation permits simpler pointer access to
structure members.
pp->age = 38; /* equivalent access operation */
• Another example,
struct Payroll lieutenant, *ppr = &lieutenant;
lieutenant.person.age = 23; /* equivalent operations */
(*ppr).person.age = 23;
ppr->person.age = 23;
13
Arrays of Structures
• The definition of arrays of structure types is the same as for arrays
of primitive types.
struct Personnel pa[10];
• Structure arrays can be initialised with an initialiser list enclosed in
braces
– the size is determined by the compiler if unspecified
struct Personnel pa[] = {
{“Fred”, 37, 1.83}, {“Mary”, 21, 1.65},
{“Joe”, 19, 2.1}, {“Cyril”, 28, 1.71}
};
14
Structures and Pointer Arithmetic
• As with primitive types, the compiler knows the size of a structure
– The size of a structure in bytes may be found via the sizeof operator.
– Pointer arithmetic on a structure pointer will compute the appropriate address offsets
automatically
• Arrays of structures behave exactly like arrays of primitive types
– Apply the usual C idioms to compute the number of elements in an array
struct Personnel pa[] = {
{“Fred”, 37, 1.83}, {“Mary”, 21, 1.65},
{“Joe”, 19, 2.1}, {“Cyril”, 28, 1.71}
};
struct Personnel *pp;
int i;
for (pp = pa; pp != pa + sizeof(pa)/sizeof(pa[0]); ++pp)
printf("%s %d\n", pp->name, pp->age);
for (i = 0; i are examples of
typedefs in the standard library designed for portability
– And more, see textbook
23
struct and Modular Design
• Functions and structures possess a synergy that permits a more
modular style of code than is possible with either feature in
isolation.
– Functions hide algorithm details behind well-defined interfaces. Client knows
what the function does, but not how.
– Structures hide data representation details behind a higher-level type
definition. Client knows the overall type, but need not know its members
(eg., Matrix, FILE).
• Used together, structures define objects and associated functions
perform operations on these objects. The client is presented with a
high-level abstraction and is shielded from details.
24
Modular Design
• Combination of C features facilitate strong modularity
– Functions and structures
– C’s visibility rules (local scope, file scope)
– Header files (*.h) and source files (*.c) for separating public and private
interfaces
• Examples from textbook code: Vector, Matrix, List
• End result:
– Code is easier to use correctly, more difficult to use wrongly.
– Details of data representation and algorithm implementation can be changed
without affecting other parts of the program
• Referred to as “decoupling” or “separation of concerns”
• Software design is all about managing complexity. (Just learning
language syntax is easy.)
25
Summary
• Basic properties of structures:
– The syntax of a struct definition.
– Accessing struct members using ‘.’ and ‘->’.
– Initialisation of structures and arrays of structures.
– Structures can contain pointers to incomplete types. In
particular, they can be self-referential.
• Eg, Linked lists
26
The next level (Beyond this course!)
• Structures provide a way of grouping associated data types.
• What if we also want to group the functionality to work on
that data with the data?
• We end up with something called an “object”
– There is an entire programming paradigm called Object Orientation
(OO)
– C++ is the OO version of C.
– We will not discuss OO further in this course, but I personally
recommend you spend a little bit of time playing with C++.
27
Homework
• Finish off LAB 5
• Finish off Assignment 1
• Over the break:
– Read Assignment 2 (will probably be posted by Friday)
• Send in your questions!
– Possibly look over LAB 7 (Structures)
– READ AHEAD IN TIM BAILEY’S TEXTBOOK
• Dynamic Memory Allocation
• I/O
• Bitwise Operations
28