User defined types, structures and unions

Sometimes, the basic set of data types defined in the C language such as int, float etc. may be
insufficient for your application.  In circumstances such as these, you can create your own data
types which are based on the standard ones.  There are three mechanisms for doing this in C:

The typedef keyword.

The typedef keyword allows the programmer to create new data types :- in a way.
You typically use the typedef keyword to improve the readability of your code and as a means
of abbreviating it.
For example,

the statement

    typedef unsigned char byte;

creates a new datatype called byte which is short-hand for unsigned char.  You can the use
this new type to declare variables as follows:

    byte a;
 

Structures

Structures are aggregate data types.  For example, you can create a structure which contains
an integer, a float and a string.  This grouping of data types into a single structure may have
particular meaning to your application.  For example, a banking application will require some
form of customer record which will probably consist of an account number, name, address,
balance and presumably other additional items.  It seems logical to store these different items
in such a way that they are accessible as a unit or using a single reference.  The struct keyword
allows us to design such a collection of data items.   A banking customer record structure could
be defined as follows:

struct Customer_Record
{
    char CustomerName[50]; /* Customer name of up to 50 characters */
    char AccountNumber[11]; /* 10 digit Account number */
    float Balance;
    char Address[1024]; /* Include 1k for storage of the customer address.
}

The above merely defines a new structure type.   To actually declare (create space for) a particular
customer record you could enter the following:

    struct Customer_Record MyRecord; /* declare a structure called MyRecord of struct type Customer_Record */

The way the variable MyRecord occupies memory may be thougth of as shown in the following diagram

Now, it seems a bit cumbersome to have to keep including the struct keyword everytime we want to declare a
variable of this type.  To shorten the declaration we could use the typedef keyword as follows:

typedef struct Customer_Record_Tag
{
    char CustomerName[50]; /* Customer name of up to 50 characters */
    char AccountNumber[11]; /* 10 digit Account number */
    float Balance;
    char Address[1024]; /* Include 1k for storage of the customer address.

} Customer_Record;

and we can then declare a customer record variable as follows:

    Customer_Record MyRecord;

Note: the symbol Customer_Record_Tag is unused.

You access the individual members of a structure using the dot (.) operator.  For example

    MyRecord.Balance = 1000000; /* wishful thinking */
 

Unions

Unions allow you to create variables which share a common memory space.   Unions are
a bit like structures, in that they appear to be an aggregate data type.  However, the main difference
is that the union members occupy overlapping memory areas.  Why would you create such a strange
variable?  Well, there are several instances in which this could be useful.  For example, you might
want 2 different ways of interpreting a given piece of data.  One "view" of this piece of data might be
as a stream of 16 bit integers, another might be as a stream of 8 bit bytes.  Don't be fooled into thinking
that unions can help you  to preform automatic type conversions from say floats to strings and so on.  They
can only allow you to interpret a given collection of bytes in memory in a number of different ways.   Personal
experience has shown me that unions are best avoided if at all posisble as they are confusing and their behaviour
can depend on the operating system/hardware platform.  In certain circumstances (which usually related
to hardware interfacing) I have found them to be useful but these were rare circumstances indeed.  The
following example shows how space is assigned to a union in a system which has a 16 bit integer length.

union SomeUnion {
    int i;
    char str[4];
}

The memory for unions of this type is assigned as follows: