Menu Close

Articles

C: Composite Types

Composite data types are user defined data types that consist of several elements grouped together. Usually data elements are stored close together in consecutive memory addresses.

There are several composite data types in C.

  • Arrays
  • Strings
  • Structures
  • Unions

Arrays

This composite data type is a group of multiple elements. All elements have same data type and are ordered by a numeric index (i ≥ 0). The elements in the array can be identified using array name and index enclosed in square brackets: array[i]. First element is array[0].

Syntax:

element_type  identifier[size];

Example:

Strings

We can define string literals in C using double quotes: “…”. However a string variable must be defined as an array of characters. Each element of a string can be identified by variable name and its index. Last element in a string is NUL character: “\0”.

Syntax:

char string_name[capacity+1] = “content”;

Example:

Structures

A structure is known as record in other computer languages. It is a group of elements. Each element has a name and type. The elements can have different types. The type of element can be also a composite type. In this case the structure is sometimes called aggregate.

Syntax:

Notes: 

  • name is optional and variable is also optional but at least one must exist,
  • each item definition is ending with “;” not with “,” as you may expect,
  • you can define one or more variables having same structure separated by comma,
  • structure declaration is ending with “;” after the variable names,
  • you can not define recursive structures, you must use pointers for this;

Example:

Unions

Union is similar to structure. In union the elements are exclusive. That is union type has a single value at a time. The memory reserved for union value is large enough to enable any value to be stored, but only last value assigned is stored. 

Example:

Alert: C will not initialize the elements of unions to correct values. You can get random values that may surprise you. Many times you’r program will compile but will have logical errors. You must test everything 10 times before you can put a C program in production.

Example:

Unexpected Output:

Bit fields

Normally, Boolean values are stored in computer memory as unsigned integers. One integer has 4 bytes. So one Boolean value will occupy 4 bytes even if only 1 byte is necessary to store one Boolean value.

To save space you can group multiple Boolean values (logic flags) into one single variable of type struct with bit fields. To define a bit field you specify the length of the field after “:”. Obvious the length must be smaller than the data type of the element.

Example:

Caution: If you assign a value that will not fit in the number of bits allocated the result can be incorrect but you get no error. In the example above the value of item three is corruptedDoes not fit in 1 byte correctly while other field is also not Boolean but is correct. It fits in 5 bits reserved by structure.

Type Alias

A type alias is a name given to user defined type. You can use keyword typedef to define a new type. The type you define can be used to declare global or local variables, parameters or function result.

Syntax:

typedef composite_type type_name; 

  • typedef ::= keyword
  • type_name ::= type alias (identifier)
  • composite_type ::= { union | struct | array }

Example:

Observe: b.two and b.three are corrupted values. This is on purpose for giving an example how wrong things can go if you are not consistent. You can forget what you meant when you do not comment your code. Then you can  do something stupid and C will just have unexpected secondary effects with no warning or error. Therefore C is not a safe language.

Example:

If the composite type is already defined, you can create a type alias after or before its declaration. C compiler is using “hoisting” technique to find forward declarations. In next example we define a list of points, and we create two points in the list.

Observe: The structure t_list is recursive and nested. It is a list of points, where a point is also a structure of two integers: x, y. This structure has only two members but it could have more.

  • We use pointer *next to connect first element with last element;
  • You can assign values for elements by name using dot notation:  .p=,  .x=, .y=

Example:

Note: In previous example a function get_s() return a structure not a pointer. This is a single result with encapsulated elements. Observe that returning a structure do not require “static” keyword for variable “s”. Since this is a structure is transferred outside of the function using “copy” unlike vectors that are pointers so they must be declared static to be returned by a function. 

Next article: Pointer Arithmetic