CSCD-255
2015-03-05 and 2015-03-10


C structs

Wikipedia page        Tutorial on the C struct

In C, arrays provide an example of a aggregate data type, in which one name provides access to multiple data values.  For the array, those data values are all of the same type

To have an aggregate data type with heterogeneous types, there is the struct.  The struct contains data members of declared types.  For instance:

struct student_record
{
   char * last;
   char * first;
   char * EWUID;   // We need to preserve the leading zeroes.
};                 // Note the closing semicolon.
This will define a block of memory containing three pointers, specifically pointers to char, and provides names for them documenting their contents.  Since in MinGW a pointer is four bytes, this defines a block of memory 12 bytes long.

The declaration of a struct does not allocate any memory but provides the definition of that aggregate data type.  It consists of the keyword struct, followed by an optional user-defined structure tag, followed by declarations between curly braces.  The declarations found there give the data type of each struct member and a user-defined name to allow access to that member.  Optionally the closing brace can be followed by names for variables of that type, but always must end in a semicolon.

The code segment above declares the data type "struct student_record" and each instance of that type will contain three pointers to access a last name, a first name, and an EWUID.  This is quite similar to a program from 03 Feb (Dialog.c) which also had three fields, but used strcpy and strcat.

C also provides a means by which the programmer can set up naming for data types — typedef.  It consists of the reserved word typedef followed by a know data type and then by the name to attach to that data type.  Thanks to the code segment above, struct student_record is a known data type following its declaration.  Consequently the following declaration can be made:
typedef struct student_record stud_rec;

From this point forward we can use the simple stud_rec instead of the more verbose struct student_record.  For instance, we can have this prototype.

// In dialog with the user, build one student record
stud_rec buildRecord();

The function will build a record satisfying the specifications of a student record and return that 12-byte memory block as its function value to be copied into the stud_rec in the main function.

// x is an array of student records
   for (k = 0; k < num; k++)
      x[k] = buildRecord();

The array is generated in the same fashion as other arrays:  either using the [] format to generate an explicitly sized array, or using a pointer for dynamic allocation of the array.

   stud_rec * x;   // Dynamic array of student records
   .  .  .  Omitted code block obtaining num
   x = (stud_rec*) calloc(num, sizeof *x);   // Could be sizeof(stud_rec)

Access to the data members is provided by the member access operator ("."):  struct_variable.data_member.  For instance,

   stud_rec record;
   . . .  Omitting segment prompting for and getting a string in buffer
   record.last = (char*) calloc(strlen(buffer)+1, sizeof(char));
   strcpy (record.last, buffer);

Demonstration program from which these code snippets come
stud_rec.txt    stud_rec.c    stud_rec.exe
Small variation:  single function receives the array of structs and initializes the array
stud_rec2.txt    stud_rec2.c    stud_rec2.exe

Back on 10 Feb we looked at an example of parallel arrays to hold information about books, specifically Harry Potter books:

That can be transformed into a program using a C struct to hold the information about the books.  Note the use of in-line code for the findMax logic.
Since this must run in a directory that contains PotterData.txt, the .exe file is not included.
Potter.txt    Potter.c    Required data file:  PotterData.txt

Two programs from Winter 2014:
To run one of these, open the .c file and have CodeBlocks do the compile and run.
Motivating a pointer to a struct:
structs1.txt    structs1.c
Showing the nesting of one struct inside another:
structs2.txt    structs2.c

Linear Algebra Example
Linear algebra deals with vectors, giving displacements in the cartesian coordinate system — the triple (x, y, z) is an example.

A program dealing with vectors can easily package the vectors as structs and pass them around.  It is most efficient to pass those structs through pointers.  Since C does "pass by value", expressly putting a struct in the parameter list means that the entire contents needs to be copied into the parameter list.  Also, if the function is intended to change the contents of a  struct, that must be passed through a pointer — for example, initializing a struct or computing the vector result of an operation such as cross product.

In this example, the program defines a struct to contain a three-component vector.  It then exercises the two operations, cross product and dot product, on a pair of user-entered vectors.
Vect.txt     Vect.c     Vect.exe

Enrichment material:
If you continue learning more C, you will find that the struct allows you to use a data structure that automatically scales to the size of the problem — the linked list.  This example shows the decomposition of numbers into a product of prime numbers.
Decompose.txt   Decompose.c   Decompose.exe
AltDecompose.txt   AltDecompose.c   AltDecompose.exe