Populating an array with functions

Hi everyone,

I need your help. I want to create an array that is going to be populated with functions and those fuctions will take some arguments (each fuction may accept different argumants).

For example I have two function

  1. int example1(int arg1);
  2. float example2(int arg2);

I want to be able to populate the array base for example an IF statement

FunctionArray[2]={};

int y=0;

if (int i==0){

FunctionArray[y]=example1(); FunctionArray[y+1]=example2();

}else{

FunctionArray[y]=example2(); FunctionArray[y+1]=example1();

}

Through searching I found something called "function pointer" but I wasn't able to create a funcionable sketch.. Any advice would be helpfull

Thanks in advance

An array of functions would imply functions all of the same type, ie the same function signature.

Why don't you tell us what you want to do, not how you think it ought to be done?

Hi AWOL and thanks for your reply,

I’ve created a sketch that identifies the type of sensors that are connected each time on the board (I’m using ESP32 programming through Arduino IDE) ig ligth sensor, temperature sensor, oxygen etc.
So, when I run the sketch then are populated two arrays, the first one contains the sensor type and the second one the measurents units corresponding to each sensor type.

I want to populate a third array with functions corresponding to each sensor type…

So, when the code executes I want to be populated three array with sensor types,units and their associated functions.

This my sketch so far in case that it helps

[code]
#include <ArduinoJson.h>
#include "Nested_Json_example.h"

//*******************************************Arrays to store sensors data************************************

// LuxMeter -> pin33
// DHT22 Sensor -> pin 32
// SHT20 Sensor -> address 0x40 (this addres is given by default fromt the manufactures

char* SensorType[8] = {}; //Array that is populated with the type of sensors that are connected on the board
byte SensorsPinArray[] = {33, 32 , 0x40}; //Array that stores the pins and address that the sensors by default are connected
char *Units[16] = {}; //Array that is populated with sensors' units ,"Lux", "C", "%", "mg/L", "ppm"

//***********************************************************************************************************



void setup() {
  Serial.begin(115200);
  dht.begin();
  sht20.initSHT20();
  delay(100);
  sht20.checkSHT20();
}

//***********************************************************************************************************

void loop() {

  int pin = 0; //This is the first element/index=0 of SensorsPinArray
  int sensorCounter = 0; // COUNT THE SENSORS CONNECTED ON THE MODULE (ESP32)

  //***************************************CHECK FOR LUMINANCE SENSOR*****************************************

  if (readLuminance(lux) > 0) {

    identifySensor(SensorsPinArray[pin], sensorCounter);

    Serial.print(SensorType[sensorCounter]); Serial.print(": "); Serial.print(readLuminance(lux)); Serial.print(" "); Serial.println(Units[sensorCounter]);

    sensorCounter++;

  } else if (readLuminance(lux) == 0) {

    Serial.print("Lux Sensor sais: Sensor it's either broken or it's disconnected"); Serial.print(": "); Serial.println(readLuminance(lux));
  }

  pin++;

  //***************************************CHECK FOR DHT SENSOR*****************************************


  //INSIDE HERE AD THE IF STATEMENT FOR DHT22 SENSOR

  pin++;
  //***************************************CHECK FOR SHT20 SENSORS*****************************************

  if (sht20.readTemperature() < 80 && sht20.readHumidity() < 120) {

    identifySensor(SensorsPinArray[pin], sensorCounter);

    Serial.print(SensorType[sensorCounter]); Serial.print(": "); Serial.print(sht20.readTemperature()); Serial.print(" "); Serial.println(Units[sensorCounter]);
    Serial.print(SensorType[sensorCounter]); Serial.print(": "); Serial.print(sht20.readHumidity()); Serial.print(" "); Serial.println(Units[sensorCounter + 1]);

    sensorCounter++;


  } else {

    Serial.print("SHT20 Sensor sais: Sensor it's either broken or it's disconnected"); Serial.print(": "); Serial.println(sht20.readTemperature());
    Serial.print("SHT20 Sensor sais: Sensor it's either broken or it's disconnected"); Serial.print(": "); Serial.println(sht20.readHumidity());
  }

  pin++;

  //AFTER THE ARRAY HAS BEEN POPULATED WITH THE SENSORS PRINT A MESSAGE WITH THE AMOUNT AND TYPE OF SENSORS

  Serial.println();
  Serial.println("Connected Sensors");
  for (int i = 0; i < sensorCounter; i++) {

    Serial.print(i + 1); Serial.print(". "); Serial.println(SensorType[i]);
  }
  Serial.println("");

  delay(1000);

  //***********************************************************************************************************

  //DYNAMIC JSON OBJECT
  StaticJsonDocument<300> doc;

  for (int i = 0; i < sensorCounter; i++) {
    JsonObject obj = doc.createNestedObject();

    if (SensorType[i] == "DHT20" || SensorType[i] == "SHT22") {

      obj["Label"] = SensorType[i] ;
      obj["Reading1"] = "Reading1" ;
      obj["Units1"] = Units[i];
      obj["Reading2"] = "Reading2" ;
      obj["Units2"] = Units[i+1];
      
    } else {

      obj["Label"] = SensorType[i] ;
      obj["Reading"] = "Reading" ;
      obj["Units"] = Units[i];
    }

    serializeJson(obj, Serial);
    Serial.println();
    
  }
  Serial.println();
  delay(5000);
}

//********************************************FUNCTIONS******************************************
//******************************SWITCH CASE TO IDENTIFY SENSOR TYPE******************************

int identifySensor(int pin, int sensorCounter) {

  switch (pin) {
    case 33:

      SensorType[sensorCounter] = "LuxMeter";
      Units[sensorCounter] = "Lux";

      break;

    case 32:
      SensorType[sensorCounter] = "DHT20";
      Units[sensorCounter] = "C";
      Units[sensorCounter + 1] = "%";
      break;

    case 0x40:
      SensorType[sensorCounter] = "SHT22";
      Units[sensorCounter] = "C";
      Units[sensorCounter + 1] = "%";
      break;

    case 30:
      SensorType[sensorCounter] = "O2";
      Units[sensorCounter] = "mg/L";
      break;
  }
}

[/code]

Perhaps you want an array of pointers to the functions you create for the sensors.

Paul

As pointed out, if you want to put the function pointers in to an array, the functions must all have the same signature. You could force that by defining all of them the same way and have the individual ones only use the arguments they need. Then, I’d wrap everything up into a struct to keep the sensor information together. Something like this:

typedef float (*FunctPtr)(uint16_t, uint16_t);

struct Sensor {
  char sensorType[10];
  char units[10];
  FunctPtr ptr;
};

Sensor mySensors[6];

void setup() {
}

void loop() {
}

I personally like the "using" syntax:

using FuncPtr = float (*)(uint16_t, uint16_t);

Pieter

PieterP: I personally like the "using" syntax:

Does it provide a tangible benefit / advantage like more robust type checking or something?

No, I just find it more straightforward to read than the typedef version, with the type you’re defining on the left hand side, not in the middle of it :slight_smile:

Thank you for your answers guys. It looks like I need function pointers but I am not sure how to implenent this,

Based on the approach of gfvalvo

gfvalvo: ``` typedef float (*FunctPtr)(uint16_t, uint16_t);

struct Sensor {   char sensorType[10];   char units[10];   FunctPtr ptr; };

Sensor mySensors[6];

void setup() { }

void loop() { }

and as this is my first time I come against function pointers can you share an example of populating an array with functions?

Thanks in advance!!

Nikosant03: I want to populate a third array with functions corresponding to each sensor type..

Why?

The final purpose is to publish JSON messages based on the aforementioned populated arrays

Even though I think this is not the right approach for your problem, here's an example of how to create an array of function pointers:

[color=#5e6d03]using[/color] [color=#000000]FuncPtr[/color] [color=#434f54]=[/color] [color=#00979c]int[/color] [color=#000000]([/color][color=#434f54]*[/color][color=#000000])[/color] [color=#000000]([/color][color=#00979c]int[/color][color=#434f54],[/color] [color=#00979c]int[/color][color=#000000])[/color][color=#000000];[/color]

[color=#434f54]// Free function declaration and definition[/color]
[color=#00979c]int[/color] [color=#d35400]add[/color][color=#000000]([/color][color=#00979c]int[/color] [color=#000000]a[/color][color=#434f54],[/color] [color=#00979c]int[/color] [color=#000000]b[/color][color=#000000])[/color] [color=#000000]{[/color]
  [color=#5e6d03]return[/color] [color=#000000]a[/color] [color=#434f54]+[/color] [color=#000000]b[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#434f54]// Free function declaration[/color]
[color=#00979c]int[/color] [color=#000000]multiply[/color][color=#000000]([/color][color=#00979c]int[/color][color=#434f54],[/color] [color=#00979c]int[/color][color=#000000])[/color][color=#000000];[/color]

[color=#000000]FuncPtr[/color] [color=#000000]myArray[/color][color=#000000][[/color][color=#000000]][/color] [color=#434f54]=[/color] [color=#000000]{[/color]
  [color=#d35400]add[/color][color=#434f54],[/color]                       [color=#434f54]// normal function[/color]
  [color=#434f54]+[/color][color=#000000][[/color][color=#000000]][/color][color=#000000]([/color][color=#00979c]int[/color] [color=#000000]a[/color][color=#434f54],[/color] [color=#00979c]int[/color] [color=#000000]b[/color][color=#000000])[/color] [color=#434f54]-[/color][color=#434f54]>[/color] [color=#00979c]int[/color] [color=#000000]{[/color] [color=#434f54]// lambda function[/color]
    [color=#5e6d03]return[/color] [color=#000000]a[/color] [color=#434f54]-[/color] [color=#000000]b[/color][color=#000000];[/color]
  [color=#000000]}[/color][color=#434f54],[/color]
  [color=#000000]multiply[/color][color=#434f54],[/color]                  [color=#434f54]// normal function (without definition)[/color]
[color=#000000]}[/color][color=#000000];[/color]

[color=#434f54]// Free function definition[/color]
[color=#00979c]int[/color] [color=#000000]multiply[/color][color=#000000]([/color][color=#00979c]int[/color] [color=#000000]a[/color][color=#434f54],[/color] [color=#00979c]int[/color] [color=#000000]b[/color][color=#000000])[/color] [color=#000000]{[/color]
  [color=#5e6d03]return[/color] [color=#000000]a[/color] [color=#434f54]*[/color] [color=#000000]b[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#00979c]void[/color] [color=#5e6d03]setup[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color]
  [b][color=#d35400]Serial[/color][/b][color=#434f54].[/color][color=#d35400]begin[/color][color=#000000]([/color][color=#000000]115200[/color][color=#000000])[/color][color=#000000];[/color]
  [color=#5e6d03]while[/color] [color=#000000]([/color][color=#434f54]![/color][b][color=#d35400]Serial[/color][/b][color=#000000])[/color][color=#000000];[/color]
  [color=#00979c]int[/color] [color=#000000]a[/color] [color=#434f54]=[/color] [color=#000000]3[/color][color=#434f54],[/color] [color=#000000]b[/color] [color=#434f54]=[/color] [color=#000000]12[/color][color=#000000];[/color]
  [color=#5e6d03]for[/color] [color=#000000]([/color][color=#000000]FuncPtr[/color] [color=#000000]func[/color] [color=#434f54]:[/color] [color=#000000]myArray[/color][color=#000000])[/color] [color=#434f54]// Iterate over all function pointers[/color]
    [b][color=#d35400]Serial[/color][/b][color=#434f54].[/color][color=#d35400]println[/color][color=#000000]([/color][color=#000000]func[/color][color=#000000]([/color][color=#000000]a[/color][color=#434f54],[/color] [color=#000000]b[/color][color=#000000])[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#00979c]void[/color] [color=#5e6d03]loop[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color][color=#000000]}[/color]

PieterP: Even though I think this is not the right approach for your problem

Do you have any altenative solution that I could implement?

Nikosant03: Do you have any altenative solution that I could implement?

No, because it's not clear to me what you want to do.

Nikosant03:
The final purpose is to publish JSON messages based on the aforementioned populated arrays

You do realize that a pointer to a function is just the physical memory location within your sketch where the code for the function is stored? Outside of this specific sketch, it will only be a number with no indication of which particular function it points to.

gfvalvo: You could force that by defining all of them the same way and have the individual ones only use the arguments they need.

How about using a void pointer for the argument? That way you can pass anything to the functions (simple types, structs, ...); each function knows what to do with the argument.

Simple example

// function prototypes
bool funcWithFloat(void *params);
bool funcWithInt(void *params);

// array of function pointers
bool (*fp[])(void*)
{
  funcWithFloat,
  funcWithInt,
};

void setup()
{
  Serial.begin(57600);
  float pi = 3.14;
  fp[0](&pi);
}

void loop()
{
  static int cnt = 0;
  fp[1](&cnt);
  cnt++;
  delay(500);
}

bool funcWithFloat(void *params)
{
  float *f = (float*)params;
  Serial.print("Printing a float: ");
  Serial.println(*f);
  return true;
}

bool funcWithInt(void *params)
{
  int *i = (int*)params;

  Serial.print("Printing an integer: ");
  Serial.println(*i);
  return true;
}

sterretje: How about using a void pointer for the argument? That way you can pass anything to the functions (simple types, structs, ...); each function knows what to do with the argument.

That would undermine the entire type system. I think casting to void * like that indicates bad design. I'm pretty sure there's a better way to achieve what OP wants to do.

Functions that operate on different types should not be in the same array. It's too easy to call the wrong function with the wrong type. The code will have undefined behavior, and the compiler won't even tell you where it went wrong.

Even if you don't agree that they shouldn't be in the same array, there are better options, like std:: variant if you have access to the STL, or a tagged union. The compiler still can't really help you, but at least you can check the type at runtime.

PieterP: Even though I think this is not the right approach for your problem, here's an example of how to create an array of function pointers:

Thank you for your answer!!

What is I have different data types function, fo example int and float?

Nikosant03: What is I have different data types function, fo example int and float?

PieterP: That would undermine the entire type system.

[...]

Functions that operate on different types should not be in the same array. It's too easy to call the wrong function with the wrong type. The code will have undefined behavior, and the compiler won't even tell you where it went wrong.

Even if you don't agree that they shouldn't be in the same array, there are better options, like std:: variant if you have access to the STL, or a tagged union. The compiler still can't really help you, but at least you can check the type at runtime.

Nikosant03: What is I have different data types function, fo example int and float?

gfvalvo: As pointed out, if you want to put the function pointers in to an array, the functions must all have the same signature. You could force that by defining all of them the same way and have the individual ones only use the arguments they need.