Using a Variable as a Function Name

Hi All,

So it's day 2 of my Arduino programming experience and amazingly I need help. I need to call a function chosen at random. So I can see how I could set up a string array containing the function names and then use a randomly generated index to pull the function name out of the array and assign it to a variable:

char* myFunctions[]={"myFunction1", "myFunction2", "myFunction3", "myFunction4", "myFunction5","myFunction6"};
long randNumber;
void setup(){
randomSeed(analogRead(0));
}
void loop() {
randNumber=random(6);
//so now myFunctions[randNumber] will give me my randomly chosen function name, but how do I call that function?
}

void myFunction1(){
//do something
}

void myFunction2(){
//do something
}

void myFunction3(){
//do something
}

etc up to myFunction6()

I found this thread which comes tantalisingly close but is a little more sophisticated than I need: Calling a function using a variable - Syntax & Programs - Arduino Forum

and if I have to delve into typedef struct etc I'm going to need a little more handholding with regard to the nitty gritty of the code structure.

Any help much appreciated, thanks.

You can't do it. Names are gone by the time the code has been built.

Mark

You can do it with an array of pointers to functions. Given that it's day two of your arduino adventure though, a switch statement would likely be an easier choice for this.

As long as all of the functions have the same return type and arguments, this will work:

typedef void (*FuncPtr)(void);  //typedef 'return type' (*FuncPtr)('arguments')
FuncPtr myFunctions[]={&myFunction1, &myFunction2, &myFunction3,&myFunction4, &myFunction5,&myFunction6};

void loop() {
  randNumber=random(6);
  //so now myFunctions[randNumber] will give me my randomly chosen function name, but how do I call that function?
  myFunctions[randNumber]();
}

Damn one step ahead of me :slight_smile:

// Do not remove the include below
#include "pointertest.h"

//
// array of functions
//
void (*funcs[6]) ();
//
// function prototypes
//
void fn1();
void fn2();
void fn3();
void fn4();
void fn5();
void fn6();
//
// other variables
//
long randomNumber;

void setup()
{
	//
	// open serial
	//
	Serial.begin(9600);
	//
	// build function array
	//
	funcs[0] = fn1;
	funcs[1] = fn2;
	funcs[2] = fn3;
	funcs[3] = fn4;
	funcs[4] = fn5;
	funcs[5] = fn6;
	//
	// setup random generator
	//
	randomSeed(analogRead(0));
}

// The loop function is called in an endless loop
void loop()
{
	//
	// generate a random number
	//
	randomNumber=random(6);
	//
	// call the function based on random number as index to function array
	//
	(*funcs[randomNumber])();
}
//
// array functions
//
void fn1(){
	Serial.write("\r\nFunction1");
}
//
// array functions
//
void fn2(){
	Serial.write("\r\nFunction2");
}
//
// array functions
//
void fn3(){
	Serial.write("\r\nFunction3");
}
//
// array functions
//
void fn4(){
	Serial.write("\r\nFunction4");
}
//
// array functions
//
void fn5(){
	Serial.write("\r\nFunction5");
}
//
// array functions
//
void fn6(){
	Serial.write("\r\nFunction6");
}
switch(randNumber)
{
case 1:
    myFunction1();
    break;
case 2:
    myFunction2();
    break;
// etc
}

Great advice everyone, thanks so much for your help. If I can avoid it I'd prefer not to go down the switch route as I'm likely to end up with a lot of these functions to call and switching will get clunky I think. So the array pointer approach has a lot of appeal for me, plus there's a real risk I might learn something along the way (and let's face it I have plenty to learn). I tried Tom's approach in the Virtronics Arduino simulator but it had a problem with the declaration and came up with this error msg:

Unknown declaration >> FuncPtr myFunctions[]={myFunction1, myFunction2, myFunction3,myFunction4, myFunction5,myFunction6};
FuncPtr myFunctions[]={myFunction1, myFunction2, myFunction3,myFunction4, myFunction5,myFunction6};

So then of course it fell over when trying to call myFunctionsrandNumber.

Highly likely I've done something silly in which case please let me know, but I guess it could also be the simulator which still has a few kinks to iron out. Would I be better off trying this on the actual device? I'll also give the #include approach a go (haven't had time yet) and will report back. Thanks again, and all further advice very welcome.

Not sure what you did, but this example compiles and works:

typedef void (*FuncPtr)(void);  //typedef 'return type' (*FuncPtr)('arguments')
FuncPtr myFunctions[]={&myFunction1, &myFunction2, &myFunction3,&myFunction4, &myFunction5,&myFunction6};
void setup()
{
  // This code will only run once, after each powerup or reset of board
  
}

void loop() {
  byte randNumber=random(6);
  //so now myFunctions[randNumber] will give me my randomly chosen function name, but how do I call that function?
  myFunctions[randNumber]();
}

void myFunction1(){
  
}
void myFunction2(){
  
}
void myFunction3(){
  
}
void myFunction4(){
  
}
void myFunction5(){
  
}
void myFunction6(){
  
}

Thanks Tom. Probably more by luck than judgement that's exactly what I did. So given that it compiles fine for you I had a closer look at the simulator and sure enough the docs say:

Limitations :
Custom Libraries, pointers, structures,classes and enums may or may not work
Other minor issues to do with complicated C++ commands
Firmata needs work
Mouse object will run but not yet implemented
Pointers are not implemented
typdef function pointers not implemented
MAC,iOS interface not implemented
simple typdefs work but typedef with enum or structs to be fixed

So I asume that's the issue. I guess you can't beat the real thing so I'll give that a go just as soon as I get my board back... Many thanks for your help.

Tom's code should work fine. I've taken his code, done away with the typedef and put in some print statements. Maybe that will help to debug it for you...

void (*myFunctions[])(void)={&myFunction1, &myFunction2, &myFunction3,&myFunction4, &myFunction5,&myFunction6};
void setup()
{
  // This code will only run once, after each powerup or reset of board
  Serial.begin(9600);
}

void loop() {
  byte randNumber=random(6);
  //so now myFunctions[randNumber] will give me my randomly chosen function name, but how do I call that function?
  myFunctions[randNumber]();
}

void myFunction1(){
  Serial.println("Function 1");
  
}
void myFunction2(){
  Serial.println("Function 2");
    
}
void myFunction3(){
   Serial.println("Function 3");
   
}
void myFunction4(){
   Serial.println("Function 4");
   
}
void myFunction5(){
   Serial.println("Function 5");
   
}
void myFunction6(){
   Serial.println("Function 6");
   
}

CharlieMcF:
Thanks Tom. Probably more by luck than judgement that's exactly what I did. So given that it compiles fine for you I had a closer look at the simulator and sure enough the docs say:

Limitations :

So I asume that's the issue. I guess you can't beat the real thing so I'll give that a go just as soon as I get my board back... Many thanks for your help.

You can use the IDE to compile it whether you have a board or not - at least you can prove to yourself that it compiles (or not).

Using the IDE (thanks wildbill, I should've thought of that) both Tom's and econjack's code compile OK so hopefully all will be well when I can try it on the board itself. I was also keen to try nicoverduin's approach but can't find the pointertest library anywhere (I have looked, honest) and of course it won't compile without it. Would someone be able to point (haha) me at it?

In case it's of interest, when I tried econjack's code in the Virtronics simulator I got this error msg:

Unknown command >> myFunctionsrandNumber
myFunctionsrandNumber;

which I guess is back to the lack of pointer implementation in the simulator.

Damn but you guys are good. Connected my board, uploaded Tom's and econjack's sketches and both worked flawlessly. Thanks again. Great community.