Aggregates
Variables of the same type can be put into arrays.
char letter[50];
defines an array of 50 characters, letter[0] being the 1st and letter[49] being the last character. C has no subscript checking; if you go off the end of an array C won't warn you.
Multidimensional arrays can be defined too. E.g.
char values[50][30][10];
defines a 3D array. Note that you can't access an element using
values[3,6,1]
; you have to type values[3][6][1]
.
Variables of different types can be grouped into a structure (like a record in Pascal).
struct person { int age; int height; char surname[20]; } fred, jane;
defines 2 structures of type person each of 3 fields. Fields are accessed using the `.' operator. For example, fred.age is an integer which can be used in assignments just as a simple variable can.
typedef creates a new type. E.g.
typedef struct{ int age; int height; char surname[20]; } person;
create a type called person and
typedef struct{ double real; double imaginary; } complex;
creates a complex type. Note that typedef creates new variable types but doesn't create any new variables. These are created just as variables of the predefined types are:-
person fred, jane;
Structure may be assigned, passed to functions and returned, but they cannot compared, so
person fred, jane; ... fred = jane;
is possible (the fields of jane being copied into fred) but you can't then go on to do
if (fred == jane) fprint(stderr,"The copying worked ok\n");
you have to compare field by field.
As you see, new variable types are easily produced. What you can't do (but can in C++ and Algol68) is extend the meaning of an existing operator (`overload' it) so that it works with the new variable type: you have to write a specific function instead.
A union is like a struct except that the fields occupy the same memory location with enough memory allocated to hold the largest item. The programmer has to keep a note of what the union is being used for. What would the following code print out?
... union person { int age; int height; char surname[20]; } fred; fred.age = 23; fred.height = 163; printf("Fred is %d years old\n", fred.age); ...
If fred started at memory location 2000, then fred.age, fred.height and fred.surname would all begin at memory location 2000 too, whereas in a struct the fields wouldn't overlap. So setting fred.height to 163 overwrites fred.age (and the 1st 4 characters of fred.surname) making fred 163 years old.