.. _Arrays:

.. raw:: html

   <script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "Arrays";ODSA.SETTINGS.MODULE_LONG_NAME = "Arrays, Structs, Enums, and Type Definitions";ODSA.SETTINGS.MODULE_CHAPTER = "Appendix A"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 17:15:26"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script>


.. |--| unicode:: U+2013   .. en dash
.. |---| unicode:: U+2014  .. em dash, trimming surrounding whitespace
   :trim:


.. This file is part of the OpenCSF eTextbook project. It was
.. auto-generated by scripts from the OpenDSA eTextbook project.
.. See https://OpenCSF.org for more details. OpenCSF is distributed
.. under a Creative Commons Attribution-NonCommercial 4.0 International
.. License (see http://creativecommons.org/licenses/by-nc/4.0/),
.. Copyright (c) 2019-2021 by Michael S. Kirkpatrick. OpenDSA is
.. distributed under an MIT open source license, Copyright (c) 2012-2021
.. by the OpenDSA Project Contributors.

.. avmetadata::
   :author: Michael S. Kirkpatrick
   :requires:
   :satisfies:
   :topic:

Arrays, Structs, Enums, and Type Definitions
============================================

As with other common typed languages (such as Java), C supports arrays of other types. When
declaring an array, the compiler must be able to determine the exact length. One way to do this is
to specify the length inside the brackets of the declaration (such as ``int array[10];``). Another
way is to provide an explicit initialization array. `Code Listing A.11 <#cla-11>`_ demonstrates this
second technique, omitting the length from inside the brackets on line 6 (although it could be
included here).

.. _cla-11:

.. codeinclude:: CLang/CodeListing-A-11.c
   :linenos: true

`Code Listing A.11 <#cla-11>`_ illustrates a key aspect of the relationship between arrays and
pointers: **Array names are implicitly pointers to their first element**. To see this, consider
lines 7 – 9; line 7 prints the *value* of ``data``, line 8 prints the address of data, and line 9
prints the *address* of ``data[0]``. When this program is run, these three lines produce the same
value as the output. The convention in C is that any array variable is an alias for the starting
address. All three of these notations can be used (and frequently are) depending on the context and
style preferences of the programmer.

`Code Listing A.12 <#cla-12>`_ extends the previous example to explore the relationship between
arrays and pointers further. Line 7 starts by declaring a pointer and initializing it to point to
the array. On this line, we could also initialize ``u32ptr = &data[0]``, but (due to convoluted type
checking rules) it is a compiler warning to initialize ``u32ptr = &data`` (despite the fact that
data and &data are the same). Line 8 sets the ``walker`` pointer in the same way.

.. _cla-12:

.. codeinclude:: CLang/CodeListing-A-12.c
   :linenos: true

Lines 13 – 23 in `Code Listing A.12 <#cla-12>`_ demonstrate the equivalency between array
dereferencing and *pointer arithmetic*. That is, when C performs an operation like ``u32ptr +
5``, it is not simply the value of ``u32ptr`` plus the number 5 in standard arithmetic; instead,
``u32ptr + 5`` requires taking the value of ``u32ptr`` (which is an address) and adding 5 times the
size of what ``u32ptr`` points to. In this case, if u32ptr stores the address ``0x7ffee0000720``,
``u32ptr + 5`` would add 20 to this value (since ``u32ptr`` is a pointer to 4-byte ``uint32_t``
values), yielding ``0x7ffee0000734``. In general terms, for an arbitrary pointer ``ptr``,
``&ptr[n]`` and ``ptr+n`` are identical for any integer ``n``; ``ptr[n]`` and ``*(ptr+n)`` also
yield the same value. (As the bracket notation tends to be more familiar, many C programmers use it
whenever pointer arithmetic is needed.)

Lines 21 and 22 do not require adding any value to the ``walker`` pointer so that it accesses the
correct location. Instead, walker is set up to *walk through* the array, accessing one element at a
time. Specifically, line 8 initializes ``walker`` to point to the first element, and the increment
field of the ``for``-loop causes walker to advance after each iteration (line 13). (Observe that it is
possible to specify multiple increments in a ``for``-loop, separated by a comma as shown with ``i++``,
``walker++``.) A subtle aspect of this increment is that it does not simply add 1 to the address
``walker`` is pointing to; rather, just like the additions on lines 18 and 20, ``walker++`` will
increment the address by the size of a ``uint32_t``. Consequently, this incrementing style is a
common technique to use a pointer to traverse through the elements of an array.

Although pointer variables can be treated as arrays, the reverse is not true. That is, even though
an array name is implicitly a pointer to the first element of the array, we cannot use pointer
notation for a variable declared as an array. In `Code Listing A.11 <#cla-11>`_ and `A.12
<#cla-12>`_, trying to access ``*data`` or ``*(data+i)`` would produce a compiler error.

`Code Listing A.13 <#cla-13>`_ illustrates a slight variation on `Code Listing A.12 <#cla-12>`_. In
this scenario, ``data`` is declared as an array of 32-bit values. Since the array consists of two of
these values, the array occupies eight consecutive bytes of memory. Line 12 declares a pointer like
before, but the pointer is a ``uint8_t*``, so it points to 8-bit values. Lines 13 – 19 will traverse
through all of the bytes of the ``data`` array, but accessing it a byte at a time instead of just
examining the two 32-bit entries. One advantage of this approach is that using a ``uint8_t*``
pointer provides a mechanism to explore the endianness of multi-byte integers. In this example,
``data[0]`` stores the 32-bit value ``0x01020304``, spread across four memory locations. Assuming
this runs on a little-endian architecture (such as x86), 0x04 is stored at the first of these four
byte locations; consequently, ``u8ptr[0]`` accesses ``0x04``, ``u8ptr[1]`` access ``0x03``, and so
on. Once the loop would get to ``u8ptr[4]``, the result would be 0x08, which is the first byte
stored for ``data[1]``.

.. _cla-13:

.. codeinclude:: CLang/CodeListing-A-13.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   It is critical to understand that C does not explicitly store the length of an array anywhere, so
   there is no way to learn this information for a pointer to an arbitrary array. Consider the
   ``data`` and ``ptr`` variables as declared below. By examining this code, we can determine that the
   ``data`` array takes up 16 bytes and consists of four consecutive 32-bit values; i.e., this portion
   of source code makes it clear that the length of the array is four.

   .. codeinclude:: CLang/BugSizeof.c
      :linenos: true

   A very common mistake is to try to use ``sizeof()`` as shown on lines 4 and 5. With one exception
   (shown on line 7), ``sizeof()`` **cannot be used to determine the length of an array**.
   Recall that ``sizeof()`` returns the number of bytes for a variable; it is not aware of the
   subdivision of those bytes into an array of consecutive elements. As such, the ``sizeof(data)`` on
   line 4 returns 16, which is the total number of bytes for the array. Similarly, the ``sizeof(ptr)``
   on line 5 returns 8, which is the size of a pointer (i.e., an address) on a 64-bit CPU
   architecture. Neither of these return the number of elements in the array.

   Line 7 is successful because we know the total amount of space for data (``sizeof(data)`` =
   16 bytes) and we know data is an array of ``uint32_t`` items (``sizeof(uint32_t)`` = 4 bytes for
   each item). Having both of these pieces of information allows us to perform this calculation. We
   cannot perform this same calculation using ``sizeof(ptr)``, however. That is, if we are given a
   pointer (such as ``ptr``) and we know that it is pointing to an array of ``uint32_t`` items, we
   cannot determine the length of the array. The problem is that ptr technically does not point to an
   array; rather, it points only to the *first element* of the array. There is no way to attach the
   additional information of the size of the array to the pointer.

   This point becomes really important later, when we discuss the relationship of arrays and functions.
   Specifically, arrays cannot be directly passed as an argument to a function call. Rather, arrays
   are always passed as pointers. Because of this fact, the length of the array must be passed
   explicitly as a separate parameter. The simplest example of this is the parameter list of
   ``main()``, which consists of an array (``argv``) and its array length (``argc``).

   .. codeinclude:: CLang/Argv.c
      :linenos: true

Two-dimensional Arrays
----------------------

One side effect of C not storing array lengths is the complexity of working with multi-dimensional
arrays. Consider `Code Listing A.14 <#cla-14>`_ as an example. Line 6 declares an array that
contains two rows of three columns each. When declaring ``data`` on this line, the 3 must be
specified within the brackets to indicate the number of columns per row. That is, this declaration
could not be written as ``data[][]``, even with the explicit initialization on the right side of the line.

.. _cla-14:

.. codeinclude:: CLang/CodeListing-A-14.c
   :linenos: true
   
.. _TwoDPtr:

.. figure:: Images/CSF-Images.A.2.png
   :align: right
   :width: 95%
   :figwidth: 40%
   :alt: Creating a virtual 2-d array with an array of pointers

   Creating a virtual 2-d array with an array of pointers

The rest of `Code Listing A.14 <#cla-14>`_ is modeled off of the structure of `Code Listing A.12
<#cla-12>`_. As in that example, there is a ``u32ptr`` that is set to point to the array (line 12).
Based on the declaration, though, ``u32ptr`` is a pointer to a ``uint32_t``. Because of this
declaration, it can be used as a one-dimensional array, but not as a two dimensional array. That is
not a problem in this case, because C stores arrays in *row-major order*; in this order, the
first element of the second row is placed immediately after the last element of the first row. That
is, ``data[1][0]`` (the same as ``u32ptr[3]``) immediately follows ``data[0][2]`` (the same as
``u32ptr[2]``). Thus, a one-dimensional array pointer like u32ptr can navigate the two-dimensional
structure by calculating its index as ``i * 3 + j`` (row times columns/row, plus the column number
of the current row). This requires, of course, knowledge of the number of columns per row. When
two-dimensional arrays are passed as arguments to functions, this additional information must be
passed explicitly as separate parameters.

`Code Listing A.15 <#cla-15>`_ demonstrates a common variation on two-dimensional arrays. In this
case, data is not declared as a two-dimensional array; rather, it is one-dimensional array of two
pointers. Its initialization in line 10 provides those two pointers: the addresses of the two arrays
``row0`` and ``row1``. Unlike the declaration structure of `Code Listing A.14 <#cla-14>`_, this
version does not guarantee that the elements can all be accessed in row-major order. The ``row0``
and ``row1`` arrays are not guaranteed to be in any particular order in memory; consequently, we
cannot say that ``row1[0]`` immediately follows ``row0[2]``. :num:`Figure <Figure #TwoDPtr>`
illustrates the pointer structure of this declaration.

.. _cla-15:

.. codeinclude:: CLang/CodeListing-A-15.c
   :linenos: true

.. _ArgvPtrs:

.. figure:: Images/CSF-Images.A.3.png
   :align: right
   :width: 95%
   :figwidth: 40%
   :alt: The argv array of command-line arguments is an array of pointers

   The ``argv`` array of command-line arguments is an array of pointers

Despite this more complex inner structure, lines 13 – 18 illustrate that the array can still be
treated like a two-dimensional array for accessing elements. This code works as an artifact of an
earlier point in this section: pointers can be dereferenced using bracket notation. In this case,
data is declared as an array of ``uint32_t*`` elements, so ``data[0]`` is a pointer storing the
address of ``row0``. Accessing ``data[0][1]``, then, is the same as accessing ``row0[1]`` because of
the pointer dereferencing.

:num:`Figure <Figure #ArgvPtrs>` illustrates a familiar example for this same concept. Consider the
command line to list files as ``"ls -ltr"``. In this case, ``argv[0]`` is ``"ls"`` and ``argv[1]``
is ``"-ltr"`` internal in the process that runs this program. Since the parameter is declared ``char
*argv[]`` (i.e., an array of pointers to ``chars``), we can see that each element is a pointer to a
string.

Structs and Packing
-------------------

Elements in an array are, by definition, all of the same type. Given the declaration ``int
data[5]``, we know that the five elements are ``int``\s and these elements occupy a single block of
consecutive bytes in memory. The total size of this block is exactly the number of elements (5)
times the size of each element (an int is typically 4 bytes). To distinguish the elements within an
array, each element has a unique index that can be used in the bracket notation. As described
previously, bracket notation is semantically equivalent to calculating the offset to a memory
location using pointer arithmetic. That is, ``data[2]`` is equivalent to ``*(data + 2)``, and both
notations refer to the calculation of a particular offset from the starting address of ``data``.

Like arrays, structs are used to create a chunk of contiguous data in memory, but with two
differences. First, the fields (rather than elements) of a ``struct`` are accessed with a name,
rather than an index. Second, the fields in a ``struct`` do not have to adhere to the same type.
`Code Listing A.16 <#cla-16>`_ illustrates both of these facts with a ``struct`` declaration for
keeping track of time records. It is important to emphasize that lines 5 – 8 only define the
structure of one of these structs (similar to defining a class in an object-oriented language like
Java), rather than creating an instance of a ``struct`` in memory. In contrast, line 13 creates an
instance as a local variable, with lines 14 and 15 initializing the fields of this struct. This
declaration and initialization could be done on a single line, similar to initializing an array;
line 13 could be extended to read ``ts = { 100, 258.9275 }``, though this style requires knowing the
specific order of elements in the ``struct``.

.. _cla-16:

.. codeinclude:: CLang/CodeListing-A-16.c
   :linenos: true

In the computer systems field, this view of structs as *objects without methods* is not necessarily
sufficient. In particular, when two different machines are exchanging data, the two systems need to
agree on the layout and interpretation of the bytes without the ``struct``. This agreement is not
necessarily guaranteed, even if the same source code is used. Different compilers may arrange the
fields in different orders, and the CPU may interpret multi-byte sequences differently due to
endianness issues. `Code Listing A.17 <#cla-17>`_ demonstrates how to perform introspection into the
layout of a ``struct`` in code.

.. _cla-17:

.. codeinclude:: CLang/CodeListing-A-17.c
   :linenos: true

Line 14 prints the size of one ``struct alternating`` instance, ``alt``. Reading lines 5 – 10
suggests that line 14 will indicate that the size of ``alt`` is 8 bytes (4 for ``a``, 1 for ``b``, 2
for ``c``, and 1 for ``d``). This intuition is wrong for typical compilers and modern hardware.
Using both the ``clang`` and ``gcc`` compilers on an x86 architecture, the compiled code indicates
that ``alt`` is 12 bytes in size. The specific layout of the memory for ``alt`` is shown in `Table A.4 <#tblA-4>`_.
To be precise, the address of ``alt`` is the address of the byte on the left,
containing the value ``0x01``; the memory addresses increase from left to right in this table. As
x86 is a little-endian architecture, the bytes of the multi-byte fields ``b`` and ``c`` are
structured with the least-significant byte on the left (indicating a lower address offset within the
``struct``).

.. _tblA-4:

.. raw:: html

   <center>
   <table class="table table-bordered">
     <thead class="jmu-dark-purple-bg text-light">
       <tr>
         <th class="py-0 center"><code class="text-light">a</code></th>
         <th class="py-0 center"><code class="text-light">??</code></th>
         <th class="py-0 center"><code class="text-light">??</code></th>
         <th class="py-0 center"><code class="text-light">??</code></th>
         <th class="py-0 center" colspan="4"><code class="text-light">b</code></th>
         <th class="py-0 center" colspan="2"><code class="text-light">c</code></th>
         <th class="py-0 center"><code class="text-light">d</code></th>
         <th class="py-0 center"><code class="text-light">??</code></th>
       </tr>
     </thead>
     <tbody>
       <tr>
         <td class="py-0 center" width="8.3%"><code>01</code></td>
         <td class="py-0 center" width="8.3%"><code>??</code></td>
         <td class="py-0 center" width="8.3%"><code>??</code></td>
         <td class="py-0 center" width="8.3%"><code>??</code></td>
         <td class="py-0 center" width="8.3%"><code>02</code></td>
         <td class="py-0 center" width="8.3%"><code>00</code></td>
         <td class="py-0 center" width="8.3%"><code>00</code></td>
         <td class="py-0 center" width="8.3%"><code>00</code></td>
         <td class="py-0 center" width="8.3%"><code>03</code></td>
         <td class="py-0 center" width="8.3%"><code>00</code></td>
         <td class="py-0 center" width="8.3%"><code>04</code></td>
         <td class="py-0 center"><code>??</code></td>
       </tr>
     </tbody>
   </table>
   <p>Table A.4: The layout of an unpacked struct with padding bytes</p>
   </center>
   <br />

The fields shown as ``??`` in `Table A.4 <#tblA-4>`_ indicate additional bytes of padding. The
compiler injects this padding because of how memory is physically access by the CPU. The compiler
can also (but does not in this case, re-order the fields if necessary. Generally speaking, bytes
that are stored in the same *memory word* can be accessed in a single CPU cycle. A memory word
is a sequence of four consecutive bytes, but these bytes need to begin at a *word boundary*
(an address that is evenly divisible by four). If we assume that alt begins at address
``0x7ffe000027c0`` (which is a word boundary), the three bytes of padding just after the ``a``
ensure that ``b`` starts at another word boundary, ``0x7ffe000027c4``. If b, instead, began
immediately after ``a`` at address ``0x7ffe000027c1``, then the contents of ``b`` would span two
distinct memory words. As a result, accessing ``b`` would now require two CPU cycles instead of just
one. This additional cycle might sound trivial (since there are billions of cycles per second), but
the cumulative effect over all programs would be significant. The padding after the d rounds up the
size of the ``struct`` to be an exact multiple of three words. This padding helps ensure other data
on the stack around the ``alt`` variable also begin at word boundaries.

But what if the code needs to adhere to a specification that the ``struct alternating`` cannot have
padding? That is, each ``struct`` instance needs to be exactly eight bytes, interpreted in the order
defined by the ``struct``. In this case, the ``struct`` needs to be declared as *packed*,
meaning that there is no padding or re-ordering allowed. To declare the ``struct`` as packed, the
only change is to modify the first line of `Code Listing A.17 <#cla-17>`_ with the packed attribute:

.. codeinclude:: CLang/Packed.c

.. topic:: Note

   .. figure:: Images/CSF-Images-Note.png
      :align: left
      :width: 100%
      :alt: Decorative note icon

   Computer systems frequently take advantage of very compact data representations, particular in the
   networking domain. Bit masks, for instance, use the individual bits within a byte to represent
   distinct pieces of information. Within the ``struct`` declaration, the individual field names are
   append with ``:n`` to indicate that the field occupies ``n`` bits. Packed structs also help with
   this data compression by ensuring that there is no padding added. Consider the following example:

   .. codeinclude:: CLang/PackedBits.c
      :linenos: true

   The declaration of ``struct bits`` indicates that one instance requires 10 bits. Since we cannot
   actually allocate data at this bit level, this instance would be padded to make it exactly two
   bytes (16 bits) in size. Among those 16 bits, the C standard does not specify an exact order. The
   fields should only be accessed through their names, as shown in line 9 – 11. It is possible,
   however, to determine the layout on a particular system through trial and error. The ``printf()``
   call on lines 15 and 16 reveal that one possible layout is as follows:

   .. raw:: html

      <center>
      <table class="table table-bordered">
        <thead class="jmu-dark-purple-bg text-light">
          <tr>
            <th class="py-0 center" colspan="8">First byte</th>
            <th class="py-0 center" colspan="8">Second byte</th>
          </tr>
          <tr>
            <th class="py-0 center" colspan="6"><em>[unnamed and unused]</em></th>
            <th class="py-0 center" colspan="7"><code class="text-light">length</code></th>
            <th class="py-0 center"><code class="text-light">urg</code></th>
            <th class="py-0 center" colspan="2"><code class="text-light">type</code></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
            <td class="py-0 center" width="6.25%"><code>0</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
            <td class="py-0 center" width="6.25%"><code>1</code></td>
          </tr>
          <tr>
            <td class="py-0 center" colspan="4"><code>0</code></td>
            <td class="py-0 center" colspan="4"><code>0</code></td>
            <td class="py-0 center" colspan="4"><code>d</code></td>
            <td class="py-0 center" colspan="4"><code>b</code></td>
          </tr>
        </tbody>
      </table>
      </center>

   Based on this illustration, the seven bits of the ``length`` field spans the two bytes, whereas
   ``urgent`` and ``type`` both reside in the second byte. The bottom line shows the hexadecimal
   representation of four bits at a time. Printing the full value, as on lines 15 and 16, produces the
   output ``0x00db``.

Enums and Type Definitions
--------------------------

From the programmer's perspective, C's built-in types and ``struct``\s are low-level primitives that
make it difficult to read and understand the code. For instance, in the case of ``struct``\s, the
type is always the full name consisting of ``struct`` and the identifier following it. In the case
of ``alt`` from `Code Listing A.17 <#cla-17>`_, its type is ``struct alternating``; its type is not
``struct``, nor is its type ``alternating``. Copying the word ``struct`` around gets tedious and it
detracts from the readability. As for the primitive types, an int indicates an integer value, but
what if there are only certain integers that are valid? For instance, consider a variable that is
used to keep track of the day of the week (Sunday through Saturday) as an integer (Sunday is 1,
Saturday is 7). Referring to day 37 might lead to an unpredictable error.

To start with the latter problem, the solution is to define an enumerated type, or ``enum``. An
``enum`` is a custom integer type that allows the programmer to use names instead of numeric
constants. `Code Listing A.18 <#cla-18>`_ declares an ``enum`` for the days of the week as
previously described. In the declaration, the values in the ``enum`` are automatically incremented.
By setting ``SUN`` = 1 (instead of allowing the default starting value of 0), ``MON`` would be 2,
``TUE`` would be 3, and so on. The advantage of the ``enum`` is that we can use these meaningful
names (``MON``, ``TUE``, ``WED``, ...) instead of memorizing numeric values. We can also declare
variables using the ``enum`` type as shown on line 6.

.. _cla-18:

.. codeinclude:: CLang/CodeListing-A-18.c
   :linenos: true

To be clear, ``enum``\s are a syntactical mechanism of convenience, not security. Internally, an
``enum`` is just an ``int``, and C does not perform any bounds checking to ensure that the values of
an ``enum`` variable (such as today) match the names or the range in the definition. Line 6 could
initialize today to be 37, or line 7 could be changed to use ``today - 452``; either would be allowed,
as today is ultimately just an ``int`` variable.

The ``enum`` keyword has the same problem as the ``struct`` keyword, in that it must be included in
the type name and passed around throughout the code. In `Code Listing A.18 <#cla-18>`_, the type of
the today variable is ``enum days``, not ``enum`` or ``days``. To make the code more readable for
both ``enum``\s and ``struct``\s, we can declare a new custom type name with the ``typedef``
keyword. `Code Listing A.19 <#cla-19>`_ uses ``typedef`` on the ``enum`` from `A.18 <#cla-18>`_ and
the ``struct`` from `A.17 <#cla-17>`_.

.. _cla-19:

.. codeinclude:: CLang/CodeListing-A-19.c
   :linenos: true

The general structure for declaring a new type is ``typedef [existing type] [new type name];``. By
convention, the new type name typically ends with ``_t`` to indicate that this is a type. Observe
that there are many such type definitions in the C standard library. For instance, the ``size_t``
type is defined (indirectly, as there are several chained type definitions involved) in the
``ctype.h`` header as shown below. The advantage of using the type definition is that it provides
additional semantics. A variable declared as a ``size_t`` is not just being used as an integer, but
as the size of something.

.. codeinclude:: CLang/Typedef.c

One common problem with type definitions for ``struct``\s,`in particular, is when there are circular
dependencies. Consider `Code Listing A.20 <#cla-20>`_ that defines a ``person_t`` type and an
``age_t`` type. In this application, each person (``person_t``) has a unique name and age, but each
``age_t`` has and unique year and pointers to up to 5 people. In other words, the person_t
definition needs to know about the ``age_t`` type, while the ``age_t`` definition needs to know
about the ``person_t`` type. The problem is that the definition of ``person_t`` (lines 7 – 10) comes
before the C compiler has learned about the ``age_t`` type (line 15); the C compiler cannot look
ahead, so using age_t on line 9 would be a compiler error.

.. _cla-20:

.. codeinclude:: CLang/CodeListing-A-20.c
   :linenos: true

The solution is to use a dummy ``struct`` definition on line 5 that matches the name on line 12. (It
is vital that the name of both ``struct`` types match.) By structuring the code this way, the
compiler is able to correctly link the type of the age field within ``person_t`` as a pointer to an
``age_t`` instance later. Once this is done, the circular definition can be ignored, as shown in
`Code Listing A.21 <#cla-21>`_. The ``person_t`` instance is able to set its age field to the
address of an ``age_t`` instance without causing a compiler error or warning.

.. _cla-21:

.. codeinclude:: CLang/CodeListing-A-21.c
   :linenos: true


