Pointers to array of functions

Sorry by my 'C' is a bit rusty in this area.
I have several arrays of pointers to function. e.g.
void (*DataLoggerFunctions[])(void) =
{
&logData,
&binaryToCsv,
&openBinFile,
&testSensor
};
and
void (*MainMenuFunctions[])(void) =
{
&doTremorStimulation,
&DisplayDataLoggerMenu
};

all functions are void func(void);

I need an array of these arrays and the syntax to call any individual function.

Do you mean an array of pointers to various functions?

Yes. My bad

Perhaps something like this?

void a() { Serial.println("a"); }
void b() { Serial.println("b"); }
void c() { Serial.println("c"); }
void d() { Serial.println("d"); }
void e() { Serial.println("e"); }

void (*m[])() = {a, b};
void (*n[])() = {c, d, e};

void (**q[])() = {m, n};

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

  q[0][0]();
  q[0][1]();
  q[1][0]();
  q[1][1]();
  q[1][2]();
}
1 Like

or

void a() { Serial.println("a"); }
void b() { Serial.println("b"); }
void c() { Serial.println("c"); }
void d() { Serial.println("d"); }
void e() { Serial.println("e"); }

void (*q[2][3])() = { {a, b, nullptr}, {c, d, e} };
1 Like

The first representation is an array of pointers to arrays which can be of different length and from the encompassing array you can’t know how many elements are in each subarrays.

The second representation is a 2D array of pointers. Each line and column have the same number of elements

Advantage of the first representation is saving memory especially if the arrays can have very different lengths at the cost of a possibly more difficult/ error prone iteration through those arrays as you’ll need special attention to the indexes to not go beyond the bounds of the subarrays.

Advantage of the second version is that it’s easy to traverse and you recognize an empty cell because it holds a nullptr

Very true. One solution would be to make all these arrays zero terminated, e.g.,

void (*m[])() = {a, b, nullptr};
void (*n[])() = {c, d, e, nullptr};

void (**q[])() = {m, n, nullptr};

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

  for (size_t i = 0; q[i]; i++) {
    for (size_t j = 0; q[i][j]; j++) {
      q[i][j]();
    }
  }
}
1 Like

Indeed - an end marker would work or the size stored in another array (only one byte if you have up to 255 entries) to save a bit of RAM

It would go better if you defined a structure for each level of arrays, I think.

typedef void (*funcPtr)(void);
struct funcTable {
   funcPtr functions[4];
};
funcTable dispatch[2];

   dispatch[1].functions[2]();

(or something like that. I hardly ever get those right on the first try.)

might consider a more informative menu implementation

#include <stdio.h>
#include <stdlib.h>

// ---------------------------------------------------------
enum { None, Menu, Func };

typedef void (*FuncPtr)(void);

void funcA (void)  { printf ("%s:\n", __func__); }
void funcB (void)  { printf ("%s:\n", __func__); }

void funcE (void)  { printf ("%s:\n", __func__); }
void funcF (void)  { printf ("%s:\n", __func__); }

// -------------------------------------
struct Menu_s {
    int         type;
    void       *sub;
    const char *desc;
};

Menu_s one [] {
    { Func, (void*) funcA, "FuncA" },
    { Func, (void*) funcB, "FuncB" },
    { None, 0,   "" },
};

Menu_s two [] {
    { Func, (void*) funcE, "FuncE" },
    { Func, (void*) funcF, "FuncF" },
    { None, 0,   "" },
};

Menu_s top [] {
    { Menu, one, "One" },
    { Menu, two, "Two" },
    { None, 0,   "" },
};

Menu_s *pM  = top;
int     idx = 0;

// ---------------------------------------------------------
void
loop ()
{
    char key = getchar ();

    switch (key) {
    case 'q': 
        exit (0);

    case 'd':       // up
        if (0 < idx)
            idx--;
        break;

    case 's':       // up
        if (Menu == pM [idx].type)  {
            pM  = (Menu_s*) (pM [idx].sub);
            idx = 0;
        }
        else  {
            ((FuncPtr) pM [idx].sub) ();
            pM  = top;
            idx = 0;
        }
        break;

    case 'u':       // up
        if (None != pM [idx].type)
            idx++;
        break;

    default:
        return;             // without printing anything
        break;
    }
    printf (" %s\n", pM [idx].desc);
}

// -----------------------------------------------------------------------------
int main (void)
{
    printf (" %s\n", pM [idx].desc);
    while (1)
        loop ();
    return 0;
}

Do you mean

int
main (void)

more stylistically desired, but not syntaxtically necessary (C has no line requriements)

You had

So that was for consistency I suppose

People do that for templates because it makes sense, it could be long line, even a simple one is long, but it makes no sense moving void or int or any other return type to another line. To be different? Sure there are thousands other ways to format your code that would enrage onlookers

?
since i preface my code examples with "consider" suggesting an approach but not necessarily a solution, and in this particular case since its from my laptop, wanted to suggest from where is might be integrated into an Arduino program

Thank you all for your contributions. The solution proposed by jfjlaros simplifies my data structures and simplifies my code accessing these functions.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.