Complex data types

Sometimes you want to group data together. The simplest example of this is the array.

An array is just a bunch of simple data types strung together one after the other, so they can be indexed by a counting variable. We have used arrays several times in the examples in this book. Arrays are declared by putting their size in square brackets after the name of the variable:

unsigned char values[14];

If the array is initialized by putting values in curly braces after an equal sign, then the compiler can count the number of items itself, and we can omit the number in the square brackets:

unsigned char values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };

We can retrieve the values in the array by using an index inside square brackets:

for( int x = 0; x < 14; x++ )
   sum += values[x];
​

Sometimes we want to group different types of data into one bundle, to keep it all in one place. We use a structure for that:

struct Throb
{
  int brightness;
  int pin;
  int increment;
};

We can then declare an instance of that structure by using the structure name:

Throb first_led;

To use the variables inside the structure, we join them to the variable by a period:

first_led.pin = P1_4;
first_led.brightness = 44;
first_led.increment = 2;

Structures can be initialized by a function called a constructor. It is a function that has no return value (not even void), and has the same name as the structure:

struct Throb
{
  int brightness;
  int pin;
  int increment;
  Throb( int b, int p )
  {
    brightness = b;
    pin = p;
    increment = 1;
  }
};

Arguments to the constructor are passed in when the variable is declared:

void
setup( void )
{
  Throb first_led( 44, P1_4 );
}

Structures can have functions inside them besides the constructor. Those functions can see the variables inside the structure, and change them.

struct Throb
{
  int brightness;
  int pin;
  int increment;

  Throb( int b, int p )
  {
    brightness = b;
    pin = p;
    increment = 1;
    pinMode( pin, OUTPUT );
  } 

  void change( void )
  {
    if( brightness > 100 )
      increment = -1;
    else if( brightness < 0 )
      increment = 1;
    brightness += increment;
    analogWrite( pin, brightness );
  }
};

These functions inside structures are called methods. The change() method in the Throb structure changes the brightness of an LED every time it is called. It remembers the previous brightness so it can slowly ramp the brightness up and down if it is called many times.

All of the internal variables and methods in a structure are public, and can be used, changed, and called by any function. If you have data you want to protect from other functions, you can declare it private:

struct Throb
{
private:
  int brightness;
  int pin;
  int increment;

public:
  Throb( int b, int p )
  {
    brightness = b;
    pin = p;
    increment = 1;
    pinMode( pin, OUTPUT );
  } 

  void change( void )
  {
    if( brightness > 100 )
      increment = -1;
    else if( brightness < 0 )
      increment = 1;
    brightness += increment;
    analogWrite( pin, brightness );
  }
};

A type of structure where everything is private unless you declare it otherwise is called a Class. You can see the Throb class in use in this example.

That example uses the operator called new. The new operator creates space for the class, and calls the constructor. This space is not freed up to be used by other functions until it is destroyed, using the delete operator. In a tiny computer like the Launchpad, this kind of memory management is seldom used.