Grouping Data with struct

Introduction

Often different types of data naturally come together in a single unit. For example, a color is a compound data type consisting of three integers, one each for the red, green, and blue channels. Usually we find it more convenient to refer to the color as a single unit, rather than three separate data values. This is particularly true when we need to pass them as parameters or create arrays where the cohesion among the red, green, and blue values might otherwise be lost.

Like many languages (Scheme included, though we do not discuss it in CSC 151), C offers programmers the ability to customize their own compound data types. C provides several mechanisms for grouping data together into logical units. Already, we have seen the use of 1-dimensional arrays to store and retrieve data of the same type using an index. In this module, we consider two additional mechanisms for collections: a struct to store data of different types, and 2-dimensional arrays to store tables. Today's reading introduces the struct concept; the next reading covers two-dimensional arrays, and the third puts the ideas of a struct and 2-dimensional arrays together to address the processing of image data.

The struct Concept

C groups variables together using structs. Using a struct, you can simplify parameters, organize data, and protect information. Conceptually, structs allow a programmer to group related data together; pragmatically, the programmer needs to be able to work with the collection of data at some times and with individual pieces at other times. Within a program, the use of structs draws upon basic syntax and semantics, as described in these readings from your textbook:

Additional Background

A struct in C is the same as a "record" in many other (pre-object-oriented) programming languages. A struct is a collection of data. Functions that operate on a struct are not embedded within the struct; rather, we write such functions separately and pass structs to them as arguments.

For example, a program for keeping track of students might use the following collection of variables:

struct student {
  int number;
  double testGrades[2];
  double grade;
};

The struct is named student while its members are number, testGrades, and grade. The name of a struct is also called a tag.

A later declaration of

struct student hannah;

will create a structure variable named hannah. The individual member variables can be referred to using the syntax variableName.memberName, as in the following example:

hannah.number = 991234567;
hannah.testGrades[0] = 10.;
hannah.testGrades[1] = 11.;
hannah.grade  = (hannah.testGrades[0] / 15. + hannah.testGrades[1] / 12.) / 2.;

The declaration

struct student csc161[30];

might be used to create an array of student records.

Using the typedef Declaration

Including the struct modifier in all variables of type struct student can sometimes feel a bit cumbersome. Alternatively, we can explicitly define a new data type to describe our student information with the following instruction:

typedef struct {
  int number;
  double testGrades[2];
  double grade;
} student_t;

and then declare our variables using this new type, with instructions like:

student_t hannah;
student_t csc161[30];

You might find it helpful to think of the typedef instruction as giving a "blueprint" for the creation of a student_t struct variable, while the declarations cause the "construction" of variables having type student_t by setting aside memory.

Although any almost name can be specified as a type using a typedef statement, a common approach uses a struct followed by an underscore and a t. For example, in the student example,

With this convention student_t is a new type for a student.

Representing Time with a Struct

The following struct may be used to represent a time value in hours, minutes and seconds format (e.g., 12:34:56.123):

typedef struct {
  int hours;
  int mins;
  double secs;
} timeinfo_t;

The timeinfo_t identifier is the struct "tag". A new type called timeinfo_t is created. (We did not call it time, because there is already a C library function called time).

Structure types may be used as return types or argument types in functions. A function that converts time values given in seconds (e.g., 12345.67) to time values given in hh:mm:ss.sss format might have the prototype:

timeinfo_t convertTime( double realTime )

and would look like:

timeinfo_t convertTime( double realTime )
{
  timeinfo_t result;
        .
        .
        .
  return result;
}

Examples

During class we may discuss some of the following examples.