Page 1 of 1

Arduino Programming for Beginners – Part 8: Arrays

Arduino Programming for Beginners – Part 8: Arrays
   0

In this eight “chapter” of our articles on how to do Arduino Programming for beginners, we will take a look at arrays – what they are and how we can work with them.

This is the eight part of a series of articles I’ve written to get beginners started with Arduino Programming in the programming language C, which I’ve written with the intend to teach my 13 year old nephew (Bram) to get started with the Arduino. After all, he wants to build a robot, but without some basic knowledge about programming, he won’t get far ….

Besides an introduction into the language C, the default language used for Arduino Programming, “Arduino Programming for Beginners” will also touch topics like how to setup an Arduino, get a developers environment running, and look at a few basic electronic parts which we connect to our Arduino.




Overview of this Chapter

  A complete overview of this course can be found here: Course Overview.

What are Arrays?

We have briefly tapped into array when we were working with strings – the array of characters.

By now we already know that an “array” (Array Data Type, Array Data Structure) can be seen as a collection of elements of the same data type, and each element can be approached individually by use of an index number. See it, in it’s simplest form, as a list. In the case of a string we did see that it was a list of char(acters).

The use of array however is not limited to just text. We could use it for any data type we can find in the C language for Arduino programming. We could for example have an array (read: list) of numbers, or lights (LEDs – which could be booleans: on or off).

We can even have an array of arrays, or an array of objects like the previously mentioned “String” objects.

An Array can be seen as a list of information pieces of the same data type,
in which we can access each individual element through index numbers.

We have already seen the simple example of a string: char Name[5] = "Hans";

Which results in an array (list) of 5 elements, each of the type “char”:

string Array
 position (index)  Content of memory slot
 0  H
 1  a
 2  n
 3  s
 4  NULL

The variable “Name” points to the memory location of the “H” character of the string, which has “0” as it’s index number!
So we can access each element in the array by using it’s index number.

How about another example, this time with booleans …

Say we 5 lights, and each light can be either ON or OFF, which translates nicely to true or false to indicate a given light is ON (true) or not (false). We could define a variable for that, let’s call the variable “LightOn” and make it an array of booleans:


bool LightOn[5];

As with other variables, we can assign values right away, however with an array we have to do it a little bit different. Unlike a normal variable, where we have only one value, with arrays we have multiple calues to assign at ones. The C language has a special notation for that: accolades. Kind-a reminds you of the accolades we used before to mark code blocks right? Well, maybe think of it in the same way. We assign a whole block at once.

This would look something like this, if we set all lights to OFF (=false) initially for all 5 lights:


bool LightOn[5] = { false, false, false, false, false };

So we list all the values between those accolades and separate the values with comma’s.

As we have seen with strings, we can access each element in the array, either for reading or writing, which can be seen in this example:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  bool LightOn[5] = { false, false, false, false, false };

  // switch lights
  LightOn[2] = true;   // switch the 3rd light on
  LightOn[4] = false;  // switch the 5th light off

  // check if light 2 is on
  if(LightOn[1]==true) {
    Serial.println("First light is ON!");
  }

  // check if light 1 is on
  if(LightOn[0]) {
    Serial.println("First light is ON!");
  }

  // if light 4 is not on, then switch light 3 on
  if(!LightOn[3]) {
    Serial.println("4th light was not on, switching light 3 on now!");
    LightOn[2] = true;
  }
}

void loop() {
  // leave empty for now
}

This is not a very exciting example, and it really doesn’t do anything cool. But it gives us examples on how to work with an array.

Note that since we created an array of booleans, the “if” statement that we used can be written shorter.

The long way would be what we did in line 12, but line 17 does the exact same thing (just for a different light). Saying LightOn[1]==true is the same as comparing a boolean (LightOn[1]) with another boolean (true), which would result in a boolean (either true or false). Since this would only return “true” when “LightOn[1]” is true as well, we might as well skip the comparison and write it just as LightOn[1]. After all, this will also only result in “true” when “LightOn[1]” is true.

A logical operator that we haven’t used yet is the “not” operator which we see in line 22.
The array element LightOn[3] will return either a true or a false. The not operator reverses that to it’s opposite … so true becomes false, and false becomes true. In the “if” statement we want to know if 4 is on, so we have to look at LightOn[3]. If “LightOn[3]” is on (true) then we do not want to execute the code in the “if” statement code block. But “if” responds to “true” and “false” and if the light is on, we get a “true”, which would trigger the “if” statement.

The not statement flips that around. So the “if” statement becomes only true if “LightOn[3]” equals false. The not makes that a true.

It’s easiest to remember by reading it out loud: if not light 4 is on then do ….

Why do Arrays start counting with zero?

Ehm you said light 4, right? Yet you typed 3 … isn’t that a mistake?

Remember with the array of character strings that we started counting with zero?
That’s true for all arrays … we always start counting with zero.

Arrays are ZERO INDEXED, which means they always start counting with zero.
This means that the index number of the first element is also zero!

Let’s go back a bit and try to remember that the variable used for the array actually points to beginning of the array – or better said: it’s a pointer to the memory location where the array starts.

That pointer points to the memory address or location of the first value in the array.
So the first value is at that memory address. See it as “memory address” plus zero.

Now the next value is stored at the following memory location, see that as “memory address” plus one.

So the index number is added to the memory address (to which the pointer points).

If the pointer says that the starting address of our “LightOn” variable is address 12345, then the value of the first LightOn[0] can be found there. The value of Light[1], the second element in the array, would then become 12345 + 1 = 12346.

Now I just took the number one to add for each element, and that’s not really correct for all data types.
As you have seen with the different data types, they can have different sizes. Some are one byte, others are 2, or even more.

You should know that memory is expressed in bytes – each location is seen as a byte.
Now if we would have an array of integers (2 bytes!), then the “plus one” trick will of course not work, and that’s the reason why we want an array of the same data types, so the computer (Arduino) knows how many bytes “plus one” would be.

As an example, say we have an array of integers. Let’s define it as: int Numbers[5];

This means that we have an array of 5 integer (int) elements, and each int takes up 2 bytes.

The first element is already pointed at by the pointer (variable).
Read that as:

memory address + ( index number * 2 bytes )

The index number for the first element is zero, so the calculation will become:

memory address + ( 0 * 2 bytes)

Multiplying a number by zero will result in zero so we get:

memory address + 0

In the end we do end up with the address the pointer was giving us to begin with.

Now let’s look at the second element (index = 1) in our integer (int) array and do the same calculation:

memory address + ( index number * 2 bytes )

memory address + ( 1 * 2 bytes)

memory address + 2

So the memory address for the second element (item index = 1) will actually result in the correct address.

Do not worry if you forget this, it’s just a basic explanation why we start counting with zero. It also shows you why defining data type is so important for the computer (Arduino), so it knows where to jump to for retrieving a value. You’ll run into this at some point in time if you continue programming, and by that time it will become second nature very quickly.

Just remember: start counting with zero!

Multi-Dimensional Arrays

In the first paragraph I had mentioned that an array can have an arrays, they can be of data type that is already an array or it can be seen as a so called “multi-dimensional array”.

Say what?

Dimensions

Ok so you might not have worked with dimensions just yet, so I’ll try to give you a simple explanation.

For simplicity reasons, see a dimension as a direction you can move in back and forth.
So for example moving left and right – which would be one dimension.
This would be horizontal, and in math often referred to as the X-axis. but never mind that. In a table we could see that as a row – see it as a shopping list.

Note that the math motion is horizontal, yet in a C-table this would be a column (vertical).

Consider the first dimensions to be horizontal (width),
which can be seen as a COLUMN in a table,
or the X-axis in math.

Now let’s assume we can also move up and down. Another dimension!
This would be vertical, and in math often referred to as the Y-axis.
Again: note that math direction and C-tabel direction are swapped!

Consider the second dimension to be vertical (height),
which can be seen as a ROW in a table,
or the Y-axis in math.

We can go further with dimensions, but I will not use those in our examples.
For those that are curious, I’m sure you’ve heard of 3D, wether it’s for a movie theatre where they show a 3D movie, of on your TV at home that can do 3D. What does 3D add? Depth!
So we can also move backwards and forward. That would be the third dimension!
In math this is often called the Z-axis.

Third dimension is depth,
which in math is called the Z-axis.

So we can come up with 3 dimension … there are more, but for most of us these are concepts are harder to grasp in our head.
By the way … the forth dimension would be moving in time.

For our array example however, we will stick to 2 dimensions for now, since drawing tables in 3D is already problematic at times, let alone trying to draw in the 4th dimension …

Single Dimensional Array

A single dimension array would just be a COLUMN – a simple list, like a shopping list. Imagine a simple array as something like this:

1D Array example
 Index  Value
 0 A
 1 B
 2 C
 3 D
 4 E

This would be a 1 dimensional array – it has only one dimension – the COLUMN. It’s simple array of 5 characters, holding the characters “ABCDE” (not to be confused with a string!). We can access each element based on its index, so to access the “C”-value we’d use: variable[2].

variable[index]

Two Dimensional Array

Now when we think about a 2-dimensional array, we work with ROWs and COLUMNs, as we have mentioned before.
Thank goodness that’s an easy one too. Think of it as a table, like for example to find a train schedule, your school roster, bowling stats, or like we see in programs like Excel.

2-Dimensional Array
 Index 2 
 Index 1
 0  1   2  3  4
 0   A  F  K  P  U
 1  B  G  L  Q  V
 2  C  H  M  R  W
 3  D  I  N  S  X
 4  E  J  O  T  Y

So we made a 2-dimensional array, or a table, holding 25 values being “ABCDEFGHIJKLMNOPQRSTUVWXY”.
This array has 2 indexes since it has 2 dimensions. Accessing values would be done as such:

variable[index1][index2]

So if we want to access the “L” character, we would say: variable[1][2].

Note that you can also write this is as: variable[index1, index2]

Assigning initial values to a simple 1D array is something we have already seen: bool LightsOn[5] = { false, false, false, false, false };
Assigning initial values to a 2D array is a little bit more complex, as it is no longer a simple “list”!
Remember that we talked about arrays in an array? Well that’s exactly what we are working with when dealing with a 2D array.

Before we learned that we can assign a “set” of values, by listing them comma separated and enclosed by accolades: { 1,2,3 }

Since we placed arrays in an array, we need to have these kind of “sets” for each column, again separated by comma’s en enclosed by accolades.
This would result in something like this: datatype name = { { set1 }, { set2 }, {set3} };

Each set should be seen like a list of values again, like: { 1,2,3 }

In a code example this could look like the code below, where we build the table we just showed!
Keep in mind, these are characters, so use a single quote!


1
2
3
4
5
boolean variable[5,5] = { { 'A','B','C','D','E' },
                          { 'F','G','H','I','J' },
                          { 'K','L','M','N','O' },
                          { 'P','Q','R','S','T' },
                          { 'U','V','W','X','Y' } };

Do you see how the “sets” contain values, comma separated and accolade enclosed? And that all the sets are comma separated and accolade enclosed again? Each “set” is seen as a “value”.

 

We could try drawing a 3-dimensional array, but as it adds depth to our table, we’d end up with a cube.

An example of how we could use a 2D array

So what would the application be for such a multi-dimensional array?
Well, imagine your Arduino is managing the lights in several rooms.
Each room has 4 number of lights and we have 3 rooms.
A table, or 2-dimensional array, let’s call it LightsOn again, could capture that.

2-D Array Example
Room:
Light: 
   1   2 
 0  true  false  true
 1  true  false  false
 2  true  false  true
 3  true  false  false

So if we want to see that in the first room, all lights are ON (LightsOn[0][0], LightsOn[0][1], LightsOn[0][2] and LightsOn[0][3] are true). This way we can capture a “array” or “grid” of information, which can be accessed easily.

Let’s say we want to test all of the lights in all of these rooms.
A “for”-loop in a “for”-loop could do this easily – which means that we do a “for”-loop inside a “for”-loop – one loop for each dimension:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#define rooms 3
#define lightPerRoom 4

void setup() {
  Serial.begin(9600);
  boolean LampenAan[rooms][lightPerRoom] = { { true, true, true, true },
                                             { false, false, false, false },
                                             { true, false, true, false } };
                             
  for(int room=0; room<=rooms-1; room++) {     // Count ROOMS
    for(int light=0; light<=lightPerRoom-1; light++) {   // Count LIGHTS per ROOM
      Serial.print("Room ");
      Serial.print(room);
      Serial.print(" Light ");
      Serial.print(light);
     
      if(LampenAan[room][light]) {
        Serial.println(" is ON");
      }
      else
      {
        Serial.println(" is OFF");
      }
    } // end of light loop
     
    Serial.println(); // print empty line after each room list
  } // end room loop
}

void loop() {
  // leave empty for now
}

So in short: we have 3 rooms, each with 4 lights. So 3 lists, each with 4 items!

Did you notice how I sneaked in those “#define” compiler directives to set a constant?
I did this intendionally, as it’s a value used in more than one place in the program:

  • At the array definiton
  • In the “for”-loops

 

Additionally: if we decide to have more rooms, or more lights per room, then we can simply change this “#define” values to what we need. No need to change anything else in the program – except for the initial array values of course.

Did you notice that I reduce these by 1 in the “for”-loops?
That’s because us humans count 3 rooms as such: Room 1, 2 and 3.
But maybe you already guessed it, for an array we start counting with zero, so: Room 0, 1, and 2.
Hence the “-1” to match the counting to what we need when accessing array elements.

Did you also pay attention to the names of the variables?
Using meaningful names for variables, and defining constants like this make a program much better readable for yourself and for other.

Did you know that a construct in the same construct (here: “for”-loop in a “for”-loop) is called “nesting“? Just a nice to know thing.

You might have noticed the comments after the closing-accolade for each code block of the “for”-loops. I usually do this so it makes it easier to see which block ends where. Especially when multiple loops are involved, this most certainly is not a bad habit and improves readability.

Even though the code might be obvious, let’s go through it quickly anyway:
We start a “for”-loop to count the rooms (room), and for each “room” we count the lights in another “for”-loop.
After the “for”-loop for the lights, but still in the “for”-loop for the rooms, you’ll notice the empty “Serial.println()” – this will print an empty line in between the lists of each room.

Don’t forget: each “for”-loop for the lights will de repeated for each room!

To be complete, the output of this program:

Room 0 Light 0 is ON
Room 0 Light 1 is OFF
Room 0 Light 2 is ON
Room 0 Light 3 is OFF

Room 1 Light 0 is OFF
Room 1 Light 1 is OFF
Room 1 Light 2 is OFF
Room 1 Light 3 is ON

Room 2 Light 0 is ON
Room 2 Light 1 is OFF
Room 2 Light 2 is ON
Room 2 Light 3 is OFF

 

 

If you have questions, just ask them below in the comment section, and keep in mind: There are no stupid questions! We all had to start at some point!

Next chapter: Arduino Programming for Beginners – Part 9: Text Input

Donation options


Donations are very much appreciated, but not required. Donations will be used for web-hosting expenses, project hardware or a motivational boost (a drink or snack). Thank you very much for those have donated already! It's truly AwEsOmE to see that folks like our articles and small applications.

Comments


There are no comments yet.
You can post your own comments by using the form below, or reply to existing comments by using the "Reply" button.



Your Comment …

Friendly request to not post large files here (like source codes, log files or config files). Please use the Forum for that purpose.

Please share:
*
*
Notify me about new comments (email).
       You can also use your RSS reader to track comments.


Tweaking4All uses the free Gravatar service for Avatar display.
Tweaking4All will never share your email address with others.