25A. More on Structures


Forward declarations

Normally, a structure type needs to be defined before you use it. But there are times when you need to refer to a structure type before its definition. In that case, use a forward declaration of the type, which is just the type heading followed by a semicolon. For example,

  struct Cell;
is a forward declaration for type Cell.

Forward declarations have a rather severe limitation. A forward declaration of type Cell allows you to use type Cell* before you define type Cell. But it does not allow you to use type Cell without a * before the definition of type Cell.


Recursive structure type definitions

A definition of structure type T can refer to type T* without a forward declaration. For example, type definition

  struct ListCell
  {
    ListCell* next;
    int       item;
  };
indicates that a value of type ListCell has two fields, one of which is a pointer to a ListCell. We will see uses of this when looking at data structures. It will also help to illustrate structure copying, which is next.


Copying structures

A structure is treated like a value that occupies a given number of bytes. For example, suppose that PairOfInts is defined as follows.

  struct PairOfInts
  {
    int a;
    int b;
  };
Assuming that an int occupies 4 bytes, a value of type PairOfInts occupies 8 bytes, enough room for two ints. Statements
  PairOfInts x, y;
  x.a = 20;
  x.b = 40;
  y = x;
create two variables, x and y, of type PairOfInts. The next two statements initialize structure x. The last statement,
  y = x;
copies the structured value in x into y. You get an exact copy.

Structure copies are done the same way no matter how you indicate the structures. For example,

  PairOfInts *p, *q;
  p = new PairOfInts;
  q = new PairOfInts;
  p->a = 20;
  p->b = 40;
  *q = *p;
copies structure *p into *q.


Shallow and deep copies

The copy that you get from an assignment statement with a structure variable is a bit-for-bit copy, also called a shallow copy. To illustrate, let's create a small data structure out of two structures.

  ListCell *A, *B;
  B = new ListCell;
  B->next = NULL;
  B->item = 7;
  A = new ListCell;
  A->next = B;
  A->item = 3;

The result looks like this, where each structure is shown with the next value on top and the item on the bottom.

Now let's illustrate copying.

  ListCell *C, *D;
  C = A;
  D = new ListCell;
  *D = *A;
The result looks like this.

Notice that C (a pointer variable) is an exact copy of A (a pointer variable), pointing to the same place. Pointer variable D has been made to point to a new ListCell, as is shown in the diagram. Assignment

  *D = *A;
copies the exact contents of *A into *D. The structure that B points to is not copied; only the pointer copied, making the next pointers in *A and *D point to the same place.

A deep copy does not do a bit-by-bit copy. Instead, when it sees a pointer in a structure, it does another structure copy. If statement *D = *A were replaced by a deep copy, we would expect to get the following.

Deep copies of structures that you create are not done automatically. If you want a deep copy you will need to write a function that performs the copy.

Why does the difference between shallow and deep copies matter to you? Generally, statement

  X = Y;
does a shallow copy. A common misconception is that it does a deep copy. That tends to lead to errors in programs. If you think that statement
  *D = *A;
does a deep copy, then you also believe that statement
  D->next->item = 60;
does not have any effect on the value of B->item. But looking at the diagram, you can see that pointer D->next points to the same structure as B, and changing one of them changes both.