Prev Next

Structures

Structures

A structure is a collection of variables, possibly of different types, occupying consecutive memory locations. To get a structure, you must declare a structure type. You can do that as in the following example.

  struct MyStruct {
    long size;
    char* name;
  };
In C++, this declaration defines a type called MyStruct. You write
  MyStruct s;
to declare a variable s of type Mystruct. (Variable s occupies eight bytes of memory, four for the long int and four for the char*. So you will find that sizeof(MyStruct) = 8.)

In C++, you are allowed to write the word struct explicitly when you declare a variable, as in

  struct MyStruct s;
and this form is required in C.

Dot notation

The parts of a structure (size and name in the example) are called the fields or the variables of the structure. To get the fields of a structure, you use "dot" notation. s.name is the name field, and s.size is the size field. For example,

  s.size = 6;
  s.name = "George";
puts values into the structure. Note that no values are in the structure until you put something there.

Note: A structure type is not the same as a structure variable. It would make no sense to write

   MyStruct.name 
since MyStruct is a type, not a variable, and has no name field to select. To use a structure, declare a variable of the structure type.

Copying structures

You can copy the value of one structure into another.

For example, if you declare variables s and t as having type MyStruct, then
  s = t;
has the same effect as
  s.size = t.size;
  s.name = t.name;
That is, the entire contents of structure t is copied into the memory occupied by structure s.

If you declare structure
  struct Complex {
    double re, im;
  };
and you declare
  Complex z,w;
then
  z = w;
has the same effect as
  z.re = w.re;
  z.im = w.im;

A difference between structures and arrays

There is an important difference between arrays and structures. To put it succinctly, the size of a structure is part of its type, but the size of an array is not part of the array’s type. So copying a structure copies all of the memory occupied by the structure. But if p and q are pointers to arrays, then

  p = q;
only makes p point to the same array as q. It is the pointer that is copied, not the array itself.

Initialization of structures

You can arrange for the fields in a structure to be initialized whenever a structure variable is created. This is part of C++, and is not available in C. Inside the structure type definition, put a function definition, without a return type, whose name is the same as the name of the structure. This function is called a constructor. For example, suppose that you want each complex number to initially 0. You can write the complex type as follows.

  struct Complex {
    double re,im;

    Complex() 
    {
      re = 0.0;
      im = 0.0;
    }
  };

Another option is to ask for the initial values when a variable is created. That can be done by creating a constructor that has parameters. For example, you might declare the complex number structure as follows.
  struct Complex {
    double re,im;

    Complex() 
    {
      re = 0.0;
      im = 0.0;
    }

    Complex(double r, double i)
    {
      re = r;
      im = i;
    }
  };
Now
  Complex z, x(1,2);
declares variable z to be initialized by the constructor without parameters (and hence to have both its real and imaginary parts initialized to 0) and x to be initialized the the constructor with parameters (and hence to have a real part initialized to 1.0, and an imaginary part initialized to 2.0).

You must use constructors that are given

You can provide any number of constructors with a structure definition. But if you provide any, then one of the constructors that you provide must be used whenever a new structure is created. (If you do not provide any constructors, some default constructors are created for you.)

When you write

  Complex c;
without any parameters after c, you are using the constructor with no parameters. If you provide at least one constructor, but do not provide a parameterless one, then this is not allowed.

Copy constructors and assignment

There are times when a structure needs to be copied. You can control how that is done in two ways.

Copy constructor
A copy constructor for type Complex has the form
  Complex(const Complex& c)
  {
    ...
  }
 
It is run inside the copy, with c set to the object that is being copied. The default one is
  Complex(const Complex& c)
  {
    re = c.re;
    im = c.im;
  }
 
but you can define it to work the way you want it to work.

Assignment
You can control how assignment is done by redefining the = operator. For type Complex, the default = operator is as follows.
 Complex& operator=(const Complex& c)
 {
   re = c.re;
   im = c.im;
   return *this;
 }
  
but you can redefine how it works. It runs in the structure that is being set, with c the structure that is being copied. *this is just the thing that is being set. So the = operator returns the structure that it changed.

Creating arrays of structures

When you create an array of structures, the constructor with no parameters is automatically run for each thing in the array. If you do not have a constructor with no parameters, then you are not allowed to create an array of that kind of structure.

Pointers to structures

It is quite common to have pointers to structures. Suppose that pointer variable p has been declared by

  MyStruct* p;
Initially, p has a junk address in it, so we would not want to look to see where it points. Let us presume that p has been given a value somehow, and we want to get the size field of the structure to which p points. That structure is *p. We can write (*p).size. For example,
  n = (*p).size;
sets variable n to hold what is in the size field of the structure that p points to.

The parentheses are required. Writing *p.size will not get you what you want, because the precedence rules of C++ indicates that *p.size is the same as *(p.size). There is a convenient abbreviation that you can use to avoid the parentheses. p -> size abbreviates (*p).size. For example, you can write

  n = p->size;

Note: The -> notation is used only when you have a pointer to a structure. If s is a structure, not a pointer, then use dot notation such as s.name, not s->name.

Allocating structures in the heap

You can get a pointer to a new structure of type MyStruct by writing
  MyStruct* ms = new MyStruct;
As you can see, ms is a variable of type MyStruct*. That is, it is a pointer to a MyStruct. It is initialized to point to newly allocated memory in the heap.

Example
  Complex* c = new Complex;
creates a variable c of type Complex*, and initializes it to the address of some newly allocated memory in the heap. It automatically runs the constructor with no parameters, making this new structure hold re = 0.0 and im = 0.0.

Example
  Complex* i = new Complex(0.0, 1.0);
creates a variable i of type Complex*, and initializes it to the address of some newly allocated memory in the heap. It automatically runs the constructor with parameters, making this new structure hold re = 0.0 and im = 1.0.


Prev Next