Array of Functions?

I wrote a number of functions or as they are called in my code "Scenes", and I want one to be called randomly at a time. I tried to make an array of functions so that I can generate a random number and that will decide the scene to be called. I made a variable "myfunctions" which is supposed to be an array of all the functions. I tried to make it a pointer and a void function and also tried making it an int, but I get the error "'myfunctions does not have a name type'". Is there a better way to make an array of functions and why am I getting this error? Thanks in advance.

int myfunctions[] =
{
Scene1(),
Scene2(),
Scene3(),
Scene4(),
Scene5(),
Scene6(),
Scene7(),
Scene8(),
Scene9(),
Scene10(),
Scene11(),
Scene12(),
Scene13(),
Scene14(),
Scene15(),
Scene16(),
Scene17(),
Scene18(),
Scene19(),
Scene20(),
Scene21(),
Scene22(),
Scene23(),
Scene24(),
Scene25(),
Scene26(),
Scene27(),
Scene28(),
Scene29(),
Scene30(),
Scene31(),
Scene32(),
Scene33(),
Scene34(),
Scene35(),
Scene36(),
Scene37(),
Scene38(),
Scene39(),
Scene40(),
Scene41(),
Scene42(),
Scene43(),
Scene44(),
Scene45(),
Scene46(),
Scene47(),
Scene48(),
Scene49(),
Scene50(),
Scene51(),
Scene52(),
Scene53(),
Scene54(),
Scene55(),
Scene56(),
Scene57(),
Scene58(),
Scene59(),
Scene60(),
Scene61(),
Scene62(),
Scene63(),
Scene64(),
Scene65(),
Scene66(),
Scene67(),
Scene68(),
Scene69(),
Scene70(),
Scene71(),
Scene72(),
Scene73(),
Scene74(),
Scene75(),
Scene76(),
Scene77(),
Scene78(),
Scene79(),
Scene80()
}

If your scene functions return void and are parameterless then this might work.

void (*doScene[81])() {
Scene0,
Scene1,
Scene2,
Scene3,
Scene4,
Scene5,
Scene6,
Scene7,
Scene8,
Scene9,
Scene10,
Scene11,
Scene12,
Scene13,
Scene14,
Scene15,
Scene16,
Scene17,
Scene18,
Scene19,
Scene20,
Scene21,
Scene22,
Scene23,
Scene24,
Scene25,
Scene26,
Scene27,
Scene28,
Scene29,
Scene30,
Scene31,
Scene32,
Scene33,
Scene34,
Scene35,
Scene36,
Scene37,
Scene38,
Scene39,
Scene40,
Scene41,
Scene42,
Scene43,
Scene44,
Scene45,
Scene46,
Scene47,
Scene48,
Scene49,
Scene50,
Scene51,
Scene52,
Scene53,
Scene54,
Scene55,
Scene56,
Scene57,
Scene58,
Scene59,
Scene60,
Scene61,
Scene62,
Scene63,
Scene64,
Scene65,
Scene66,
Scene67,
Scene68,
Scene69,
Scene70,
Scene71,
Scene72,
Scene73,
Scene74,
Scene75,
Scene76,
Scene77,
Scene78,
Scene79,
Scene80
};

then you would call an array member function with:

int i = validly_constrained_random_number;
doScene[i]();

@matmanj is 99.99% right. You need an array of function pointers, NOT an array of functions. But, the call to the function needs to be (at least when I compiled it):

(*doScene[i])();

Also, let the compiler figure out how big the array needs to be:

void (*doScene[])(void) = {
Scene0,
Scene1,
.
.
.
Scene80
};

Mine compiles too - I think it's called an implicit pointer conversion.

Two ways to do this.

Function pointers

The oldschool "C" way to do it is with an array of functions.

When make a function named "foo", you are creating a name, an identifier. That identifier has a type - it's type is 'pointer to function'. You can assign the value of foo to a variable of the same type. When you call a function by putting parenthesis after its name, C treats this as an operator like any other. this means that if you put parenthesis after anything of type 'pointer to function', it's a function call.

int foo() { return 1; }
int (*bar)() = foo;
int baz() { return 2; }
int (*quux[])() = {foo, baz};

int weeble() {
  int i;
  i = foo();
  i = bar();
  i = baz();
  i = quux[1]();
  return i;
}

VIrtual methods

In C++, you do this kind of thing my having arrays of object pointers with virtual methods.

The advantage of this is that you can bundle state into the object. Here's a somewhat complex example. I define two types of 'thing doer', one with a 'rate', and one with a 'rgb'. I then make an array of things with different initialization parameters.

Although this example is complex, it contains most of the stuff that you need to make this kind of design work.

struct ThingDoer {
  const byte pin;
  ThingDoer(byte attachPin) : pin(attachPin) {}
  void setup() { pinMode(pin, OUTPUT); }
  virtual void doThing();
};

struct Blinker : ThingDoer {
  uint32_t rate;
  Blinker(byte attachPin, uint32_t rate) : 
    ThingDoer(attachPin), rate(rate) {}
  void doThing() { /* whatever, using pin and rate */ }
};

struct RGB : ThingDoer {
  int rgb;
  RGB(byte attachPin, int_t rgb) : 
    ThingDoer(attachPin), rgb(rgb) {}
  void doThing() { /* whatever, using pin and rgb */ }
};

ThingDoer *thing[] = {
  new Blinker(2, 25),
  new Blinker(2, 50),
  new RGB(2, 0x667),
  new RGB(2, 0xF82)
};

void doAll() {
  for(int i = 0; i < sizeof(thing)/sizeof(*thing); i++) {
    thing[i]->doThing();
  }
}

void setup() {
  for(int i = 0; i < sizeof(thing)/sizeof(*thing); i++) {
    thing[i]->setup();
  }
}

gfvalvo:
@matmanj is 99.99% right. You need an array of function pointers, NOT an array of functions. But, the call to the function needs to be (at least when I compiled it):

(*doScene[i])();

This is not the case - not unless you have actually declared an array of doubly indirect function pointers. Id' be interested in seeing the whole code you compiled.

See my page about function pointers.

In particular the part headed: "Putting functions into an array".

Example code:

void doAction0 ()
 {
 Serial.println (0);
 }

void doAction1 ()
 {
 Serial.println (1);
 }
 
void doAction2 ()
 {
 Serial.println (2);
 }

void doAction3 ()
 {
 Serial.println (3);
 }

void doAction4 ()
 {
 Serial.println (4);
 }

typedef void (*GeneralFunction) ();

// array of function pointers
GeneralFunction doActionsArray [] =
 {
 doAction0,
 doAction1,
 doAction2,
 doAction3,
 doAction4,
 };

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  int action = 3;   // 3 is an example

  doActionsArray [action] ();
  }  // end of setup

void loop () { }

PaulMurrayCbr:
This is not the case - not unless you have actually declared an array of doubly indirect function pointers. Id' be interested in seeing the whole code you compiled.

Here ya go. Compiled and run on ESP8266 Huzzah and a SparkFun OpenScale Board (because I had one sitting around, ATMEGA328P).

void dog1(void);
void dog2(void);
void dog3(void);

void (*myPointer[])(void) = {
  dog1,
  dog2,
  dog3
};

void setup() {
  Serial.begin(115200);
  for (uint8_t i = 0; i<3; i++) {
    (*myPointer[i])();
  }
}

void loop() {
}

void dog1() {
  Serial.println("Function dog1 has been called");
}

void dog2() {
  Serial.println("Function dog2 has been called");
}

void dog3() {
  Serial.println("Function dog3 has been called");
}

You can remove the dereferencing of the function pointer - the compiler knows what you want. And you can re-factor to get rid of the prototypes:

void dog1() {
  Serial.println("Function dog1 has been called");
}

void dog2() {
  Serial.println("Function dog2 has been called");
}

void dog3() {
  Serial.println("Function dog3 has been called");
}

void (*myPointer[])(void) = {
  dog1,
  dog2,
  dog3
};

void setup() {
  Serial.begin(115200);
  for (uint8_t i = 0; i<3; i++) {
    myPointer[i]();
  }
}

void loop() {
}

There's a better way than rearranging the functions. The IDE inserts the prototypes immediately before the first function definition in the .ino file. Since the customary order of a C++ source file has #includes first, global variables second, a function definitions last, the prototypes will typically be inserted after the globals so they will be out of scope when initializing the array of function pointers.

The easy fix is to put a dummy function definition (not a prototype) above the globals and after the #includes. Just a blank function like this will do:

void dummydummydummy() {}

This will make the IDE put the prototypes above this function, so they'll be above the globals.

1 Like

Ooh - If your Scene functions are nice and short you could declare them inside the array as closures like so...

void (*doScene[])() {
[]{//scene 0 function code},
[]{//scene 1 things},
[]{scene 2 stuff}
}

You could. I prefer to do things explicitly rather than relying on the IDE to insert stealth function prototypes. Old School I guess. YMMV.

gfvalvo:
You could. I prefer to do things explicitly rather than relying on the IDE to insert stealth function prototypes. Old School I guess. YMMV.

There's no function prototypes in this method. All code required for this array is contained in the array. It's using implicit conversion of captureless lambdas to pointers to anonymous functions. This does mean that the array has to be initialized prior to being referenced.

matmanj:
There's no function prototypes in this method. All code required for this array is contained in the array. It's using implicit conversion of captureless lambdas to pointers to anonymous functions. This does mean that the array has to be initialized prior to being referenced.

Pretty sure gfvalvo wasn't responding to you, but to me and Nick.

freebird4446:
I wrote a number of functions or as they are called in my code "Scenes", and I want one to be called randomly at a time. I tried to make an array of functions so that I can generate a random number and that will decide the scene to be called.

If that's all the goal is, I'd probably use a switch/case statement. It's just more explicit, easier to follow the syntax (for me anyway). Don't forget the "break" part of it if you want to exit the block.

Maybe you already considered that and dismissed it. Just saying, that's probably what I'd do.

Jiggy-Ninja:
Pretty sure gfvalvo wasn't responding to you, but to me and Nick.

Correct, mine was a pure ‘C’ solution and I personally prefer explicit function prototypes. Sorry for the confusion.

And, you were both correct. Dereferencing the function call is not required.