Secret Code

Functions and Multi-Dimensional Arrays

Oliver Higgins

Issue 4, October 2017

Repetitive tasks can be made more efficient, and you can handle data in a convenient way.

In the world of programming, functions are one of the most valuable tools you can use. In our ultimate quest to do as much as we can with as little code as possible, the function is probably only second to the loop, for the sheer number of lines it can save.

WHAT IS IT?

When writing code, we will often be faced with repetitive tasks, and while loops can serve a purpose, they are not always the right tool for the job. The function is another tool in the arsenal; it is a simple but elegant way to do a single thing. In best practice, you should code your functions to do a single thing and do it well.

Functions provide us with a way of putting a repeated section of code in a single place. We can then “call” it from any point in our program. It serves multiple purposes: it provides a single point to make code changes to the related code, it promotes reusability of your code, and will significantly speed up development time.

THE ANATOMY OF THE FUNCTION

No matter whether a function returns a value or not, the structure is very similar. The following is an example of pseudo code for a basic function that does not return a value.

PSEUDO CODE:

void myFunction() 
  do something; 

ARDUINO:

void myFunction(){ 
   do something; 
{

PYTHON:

def myFunction: 
   do something

We would use this in your programs where you have a single defined output that needs to be done. It could be as simple as sending an error message to the user, or it may be to move a servo a given distance. For example, the simplest implementation for this would be based on the trusty “Hello World” example. Our typical “Hello World” includes the minimum code (about one line) required to start the program and output a message. We will modify this to create the function that prints “Hello World” for us.

HOW TO USE IT

ARDUINO/C:

void printHelloWorld(){ 
  Serial.println("hello, world!"); 
}
void setup() { 
  Serial.begin(9600); 
  printHelloWorld(); 

void loop() { 
  //not used 

PYTHON 3:

def printHelloWorld():
  print("Hello World")
  return
printHelloWorld()

You can see in this example that we put the function in the code before we call it. Now most modern languages will work no matter where you put it, but we have had experience with code that compiles fine, yet the execution is erratic simply because functions were out of sequence.

PASSING A VALUE OR VALUES

This is good for calling a simple function, but what if you frequently need to calculate something complex? We can send variables to the function via parameters, and we can get the function to output a variable of the final result.

Functions can only ever return one thing (I want to say only one variable here, but arguably you could return an object or even a dataset. The important thing to understand is that you can only ever return one of them).

Here is an example of a function that will take a single parameter; in this case it’s an “int”:

ARDUINO:

void myFunction(int x){ 
  Serial.println(x); 

PYTHON 3:

def myFunction(x):
  print(x)
  return

MULTIPLE PARAMETERS

ARDUINO:

void myFunction(int x, int y, int z){ 
  Serial.println(x+y+z); 

PYTHON 3:

def myFunction(x,y,z):
  print(x + y + z)
  return

RETURNING A VALUE

Functions are great at doing simple repetitive code and having it in a single location, but one of the most powerful elements of functions is to return a value to the user. As I’ve said, functions can accept multiple inputs but can only ever return one item. In very simple terms we can input several integers and return the result of our math as a single integer.

To instruct the function that will be returning something, we need to replace the void at the start of the function with the type of variable we will be returning. In the following example we are going to return an integer by specifying “int” at the beginning.

ARDUINO:

int myFunction(int x){ 
  return x+1; 

PYTHON:

def myFunction(x):
  return x+1

WORKING EXAMPLE

This is a working example of a function that takes a single argument and then returns a value. In this case, we need to regularly calculate the circumference of a circle. The function takes one argument, an integer “d”, which is the diameter. The function then calculates and returns a float, calculating the circumference by multiplying d (diameter) with pi to 100 decimal places. In the case of the Python example, the variable types are defined by the compiler.

ARDUINO:

float myPiFunction(int d){ 
  return d*3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; 

void setup() { 
  Serial.begin(9600); 

void loop() { 
  Serial.println(myPiFunction(3)); 
  delay(2000); 

PYTHON:

def myPiFunction(d):
  return d*3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
print(myPiFunction(3))

NOTES ON FUNCTIONS

Most languages will allow you to place functions at any point outside the main script or loop. However, it is best practice, and I would strongly encourage you to place your functions above and before you use it, in a final sense. While you will not get a compile error, we have seen this be the cause for some strange issues, especially on the Arduino platform.

NAMING CONVENTIONS

Function names should start with verbs, such as “setTrap” and “getDeadVermin”, if the function changes the state of the program; and nouns if they’re used to return a certain value.

MULTI-DIMENSIONAL ARRAYS

In Issue 3 we discussed the role that arrays play in the world of programming. We can extend the array functionality to create a richer and more dynamic structure. We do this by creating a multi-dimensional array.

While an array has 1 dimension, an object with 2 or more dimensions is called a matrix. For the rest of this article we'll work with 2 dimensions only.

Please note: in this article, we will focus on ANSI-C style syntax, because Python 3 uses a different interpretation of its lists, and does not directly correlate with the general interpretation and syntax.

The declaration is similar to a single dimension array; we simply add a second square bracket with the number of elements required in the second dimension. The simplest way of thinking about the multi-dimensional array (i.e. matrix) is that it is an array of arrays; although, it may be better to think of them as a matrix or grid. When we declare an array, we give it the total number of elements in both the X and Y dimensions.

To declare a multi-dimensional array we using the following code, which has three rows with each row having four columns.

int myArray[3][4]

How do we put in data?

You can directly access the by:

myArray[2][1]=5;

or

int myArray[3][4] = { 
  {0, 1, 2, 3} ,   //row indexed by 0 
  {4, 5, 6, 7} ,   //row indexed by 1 
  {8, 9, 10, 11}   //row indexed by 2 
};

or

int myArray[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

To access the information in a give variable we address the array like so:

myArray[2][1]

This is similar to creating a table in Word or using a spreadsheet. By addressing the X and Y coordinates, we can pragmatically and systemically traverse (that is, work our way through) the array and pull out the required information.

COL 0 COL 1 COL 2 COL 3
ROW 0 [0][0] [0][1] [0][2] [0][3]
ROW 1 [1][0] [1][1] [1][2] [1][3]
ROW 2 [2][0] [2][1] [2][2] [2][3]

A word of warning: there are two ways in which you can use this type of array; one is similar to a database or record set, where each row contains a subset of data, and each column is an element. To access the array in this manner, you use a nested loop conjugation, consisting of two loops. The first loop traverses the rows, the second traverses the columns. This is shown below.

void setup() { 
  Serial.begin(9600); 

void loop() { 
  int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8}}; 
  int i, j; 
  for ( i = 0; i < 5; i++ ) { 
    for ( j = 0; j < 2; j++ ) { 
      Serial.print("a["+String(i)+"]"+"["+String(j)+"] "); 
      Serial.println(a[i][j]); 
    } 
  } 
  delay(10000); 

The alternative is to use the multi-dimensional array as a grid. The best example of this is the battleships game. If we were to implement a version of this game, we would need to create four matrices; one for each player’s ships and one for each player’s hits/misses. Each player would align their ships to the grid creating a “map” of the locations. Each time the other player “fires” a shot (e.g. “B7”), we need to take the reference and see if there is a ship located at that location. If there is then we mark the alternate matrix as a hit, otherwise we mark it as a miss. The game could include error checking to indicate that shots may have already been fired in a given location or supply alternative feedback.

In this context we do not access the information in a linear looped way; instead, we are addressing the individual elements directly.

myArray[2][1]

We need to clearly understand the purpose of the multi-dimensional array before we access it in our code. In this context, the multi-dimensional array is two dimensions: X and Y. Depending on your implementation you could make it three or more dimensions; however, better coding solutions exist for things such as this. The battleships game could easily work as a 3D array, with the 3D “Z” dimension allowing each of the players’ boards to be allocated in this dimension.

CODE WITH INTENT

This might sound like a motivational speech, but it's not. What we mean here is that when you're designing your functions, give them a single purpose. Don’t make several things happen or multiple variables change with each function. While this may sound trivial, it becomes a serious headache in large multi-file programs or object-orientated environments.

Functions can call functions, and those functions can call functions, so do not be afraid to break your code into atomic structures (an atomic structure is one that does a single job).

This simple change to your coding habits will make code supervision and bug tracking much faster and simpler.