Part B - Foundations
Compound Types II
Define an array of instances of a compound data type
Define a compound data type that contains another compound data type
Outline a walkthrough technique for programs that include compound data types
"Much computing involves creating collections of various
forms of objects and then manipulating such collections. Reading characters
into a string and printing out the string is a simple example. A
class with the main purpose of holding objects is commonly called
a container" (Stroustrup, 1997)
Arrays
| Containers
| Walkthrough
| In-Class Exercise
| Summary
We can create complex compound types from simpler ones in the same
way that we create simple compound types from primitive types.
We can define an array of instances of a compound type just like we
define an array of elements of primitive type. We can also include a
compound type as a data member in a more complex type.
In this chapter, we describe the syntax for creating and accessing
arrays of instances of compound types along with
the syntax for creating and accessing compound types that contain
other compound types. We conclude by presenting a technique
for walking through code that includes instances of a compound
type.
Arrays
To declare an array of instances of a compound type, we suffix
the instance identifier with a brackets-enclosed number.
This number, which is an integer constant or integer-constant
expression, specifies the number of elements in the array.
For example, to define an array of 40 Students, we write:
struct Student student[40];
|
The rules that apply to arrays of primitive types apply
equally to arrays of compound types:
- element indexing is 0-based - the first element is
student[0]
- student[i] refers to the
i+1-th element of the array
- the name of the array alone refers to the address of its
start - student is the
same as &student[0]
Alternative to Parallel Arrays
Parallel Arrays
Parallel arrays are a traditional technique for organizing
data in tabular form.
For instance, we store the student numbers and grades
of 40 students in two separate arrays
int no[40];
char grade[40][14];
|
To initialize the first three elements of these two parallel
arrays, we write:
int no[40] = {10001, 10002, 10003};
char grade[40][14] = {"CAC", "CBB", "AAB"};
|
The number of and the grades for the third student are
given by no[2] and grade[2] respectively. The common index
is a defining feature of parallel arrays.
Array of Instances
An array of instances of a compound data type provides a
simple alternative to parallel arrays. Each instance
holds the data for an entire row in the table. The
members of each instance hold the field data for a
row. Instead of
defining two parallel arrays, we write:
struct Student {
int no;
char grade[14];
};
struct Student student[40];
|
The number of and the grades for the third student
are given by student[2].no and
student[2].grade respectively.
To initialize the members of the first three elements
of the array, we
write:
struct Student student[40] = {{10001,"CAC"},{10002,"CBB"},{10003,"AAB"}};
|
We arrange the data values instance by instance and
the interior braces distinguish the data values for one instance
from those for another instance. The interior braces are
optional and we may simply list the values
in the order in which they are stored in memory
struct Student student[40] = {10001, "CAC", 10002, "CBB", 10003, "AAB"};
|
Passing an Element of an Array of
Instances
If we pass a single element of an array
to a function, the function receives a copy of that
element and stores it in a separate instance.
Within the function, we refer to the members of the copied
instance and not the original element:
// Student.h
struct Student {
int no;
char grade[14];
};
// main.cpp
#include <iostream>
using namespace std;
#include "Student.h"
void display(const struct Student*);
int main() {
int i;
struct Student student[40] = {10001,"CAC",10002,"CBB",10003,"AAB"};
for (i = 0; i < 3; i++)
display(&student[i]);
}
void display(const struct Student* s) {
cout << s->no << ' ' << s->grade << endl;
}
|
Containers
We call a compound type that holds one or more other compound types
a container type. Defining a container type allow us to
include other types without describing their implementation
details. We describe their implementation
details outside the container type. Because
we describe the included type and the container type separately,
we can update them independently.
We call a compound type that contains another compound type
throughout the container's lifetime a composition.
One example of a container type is a system box, which contains
a motherboard, which contains a CPU, which contains an ALU.
Another example is a section of a course, which contains a list of
enrolled students. For this case, we define a
Section type that contains
an array of Student types:
struct Student {
int no;
char grade[14];
};
struct Section {
int noOfStudents;
struct Student student[40];
};
|
Note that a compound type may NOT contain an instance of its itself.
struct Section {
int noOfStudents;
struct Section section; /* ERROR */
};
|
Member Access
Dot, arrow, and subscript syntax applies to
compositions as well as to simple compound types. To define
an instance of a Section, we write:
To set the number of students in abc123a to 23, we write:
abc123a.noOfStudents = 23;
|
To set the student number of the sixth student to 123-456-789, we write:
abc123a.student[5].no = 123456789;
|
To set the third grade of the sixth student to an 'A', we
write:
abc123a.student[5].grade[2] = 'A';
|
We say that abc123a has a
student with student number
123456789, whose third grade is 'A'.
Walkthrough
Walking through an application that includes instances of compound data
types requires some care in the preparation of the walkthrough
table(s). The table for the following program is shown below.
#include <iostream>
using namespace std;
struct A {
int x;
double r;
};
void foo(struct A* c);
struct A goo(struct A d);
int main( ) {
struct A a = {4, 6.67}, b;
foo(&a);
cout << "00" << a.x << '.' << a.r << ".111" << endl;
b = goo(a);
cout << "00" << a.x << '.' << a.r << ".112" << endl;
cout << b.x << '.' << b.r << ".113" << endl;
}
void foo(struct A* c) {
int i;
i = c->x;
c->x = c->r;
c->r = c->x % i + 202.134;
}
struct A goo(struct A d) {
struct A e;
d.x = d.r - 62;
e = d;
return e;
}
|
The table includes:
- the return type for each function
- the name of each function
- the data type of each instance
- the name of each instance
- the data type of each member or variable
- the name of each member or variable
We reserves a separate line for the
addresses of the instances and variables that
are pointed to:
int |
void |
struct A |
main |
foo |
goo |
struct A |
struct A |
struct A* |
|
struct A |
struct A |
a |
b |
c |
|
d |
e |
1000 |
100C |
1018 |
101C |
1020 |
102C |
int |
double |
int |
double |
|
int |
int |
double |
int |
double |
x |
r |
x |
r |
|
i |
x |
r |
x |
r |
|
|
|
|
1000 |
|
|
|
|
|
|
|
|
|
1000 |
|
|
|
|
|
|
|
|
|
1000 |
|
|
|
|
|
|
|
|
|
1000 |
|
|
|
|
|
|
|
|
|
1000 |
|
|
|
|
|
Output:
In-Class Exercise
Complete the Handout on
Walkthrough on A Compound Type.
Summary
- to allocate memory for an array of instances of a compound
type use the same bracket notation as with primitive
types
- to access an element in an array of instances of a compound
type use the same subscript notation as with primitive
types
- to access a data member
of an element in an array of instances of a compound type follow the bracket notation with the dot
operator and the name of the data member
- a compound type may contain an instance of another compound
type as one of its data members
- a container type is a compound type that contains an instance of another compound
type as one of its data members
- to access an instance of a compound type within an
instance of a container type, use the dot operator followed
by the name of the instance that is within the
container type
- to access a data member of an instance of a compound type
within an instance of a container type, use the dot
operator followed by the name of the instance
within the container type, followed by the dot operator and
the name of the data member
|