tags:

views:

145

answers:

6

In C, is there a way to call a function with arguments stored in some array? I'm a C newbie, I'm not even sure if this is right but e.g.:

void f0(int a) { ... };
void f1(int a, int b) { ... };
void f2(int a, int b, int c) { ... };

int array[5][2][?] = [
    [&f0, [5]],
    [&f1, [-23, 5]],
    [&f2, [0, 1, 2]],
    [&f2, [1235, 111, 4234]],
    [&f0, [22]]
];

int i;
for (i = 0; i < 5; i++) {
    APPLY?(array[i][0], array[i][1])
}

PS: What kind of structure should I use when the array's items vary in length?

In Python, this would be:

def f0(a): ...
def f1(a, b): ...
def f2(a, b, c): ...

array = [
    (f0, (5,)),
    (f1, (-23, 5)),
    (f2, (0, 1, 2)),
    (f2, (1235, 111, 4234)),
    (f0, (22,))
]

for f, args in array:
    apply(f, args)
+2  A: 

Not really, no.

A better way to do this in C would be to define your functions to all have the same signature, like:

void f0(int size, int elements[])

and then pass arrays of the appropriate size to your functions.

// this is a function pointer
void (*x)(int, int[]); 
...
// set x to point at f0
x = f0;
// call x (ie: f0) with 1 element from position 5 of array
x(1, &(array[5]));
Laurence Gonsalves
This is the best solution, passing the size of the array and then the actual array.
rupert0
I'm not sure if I understand: I should add the lengths of items into the array. Ok. But how do I call the functions with the items as arguments?
Ian_K
Look at the last line of the answer. That's calling f0 passing it a 1 (for the number of args) plus a pointer to the fifth position in the array. Actually, I'd probably make 'array' into an array of structs (instead of a 3D array) where each struct has 3 fields: the function, the number of args, and an array of args. Then you'd say `(array[i].f)(array[i].n, array[i].args)` in your loop.
Laurence Gonsalves
A: 

There might be a simpler way to accomplish your goal, what are you trying to do? and what are your limitations with data etc?

Joel
I'm trying to write a simple vector graphic viewer. A user could specify, e.g.: rectangle, line, line and I would like to draw that. I can do it with a switch() but was wondering whether it is possible to do it faster.
Ian_K
You could use a struct.here's some info on structs (a simple object) http://cprogramminglanguage.net/c-structure.aspxstruct shape{ int numberOfPoints; int points[4]; char shapeType[10];}You could store the shape type in the shapeType string, and the points in the point array, and pass each index to a function to plot the points.
Joel
+2  A: 

It's possibly to have variable arity functions in C, but the mechanism is clunky and has certain restrictions, namely, there must be at least one fixed parameter, and you need to be able to tell from the fixed parameters or from the variable parameters themselves where the end of the variable list is.

A more typical solution, one that plays to C's strengths rather than its weaknesses, is something like this example. (Updated with function pointers.)

#include <stdio.h>

void f1(int, int *);
void f2(int, int *);

struct BoxOfInts {
    void (*f)(int,int *);
    int howMany;
    int theNumbers[4];
} intMachine[] = {
    {f1, 1,  { 5,  }},
    {f2, 2,  { -23, 5  }},
    {f1, 3,  { 0, 1, 2  }},
    {f2, 3,  { 1235, 111, 4234  }},
    {f1, 1,  { 22,  }},
    { 0 }
};

void dispatch(void)
{
    for(struct BoxOfInts *p = intMachine; p->f; ++p)
        (*p->f)(p->howMany, p->theNumbers);
}

void f1(int howMany, int *p)
{
    while (howMany-- > 0) {
        int t = *p++;
        printf("f1 %d %d\n", howMany, t);
    }
}

void f2(int howMany, int *p)
{
    while (howMany-- > 0) {
        int t = *p++;
        printf("f2 %d %d\n", howMany, t);
    }
}

int main()
{
  dispatch();
  return 0;
}
DigitalRoss
What are the {} at the top? Variable length arrays?Also, I wanted to call various f-s (f0, f1, f2), how do I add them to the array and call the appropriate one in dispatch?
Ian_K
Note also that stdarg.h doesn't allow for building arbitrary argument arrays, only copying ones that already exist. You'd still have to do the marshalling in assembly, or via a huge array of helper functions a-la Glib/Gtk.
Andy Ross
The `{}` syntax defines an *initializer-list`, these sometimes-optional groups tell the compiler when a list for a given aggregate element is done. I didn't realize you wanted different functions for reasons other than arity. I've put them in the revised example.
DigitalRoss
Totally what I was looking for, thanks a lot!
Ian_K
A: 

I think perhaps you just want:

array[i][0](array[i][1]);

To call a function from its pointer in C only requires the function call operator, which is parentheses.

Possibly useful link: http://boredzo.org/pointers/

Rob F
That's interesting. What format should be the arguments stored in? I mean, to call a function f(int a, int b) is it ok to write:int[] a = [1, 2];void *pointer = *pointer(a);?I'm totally lost....
Ian_K
That's a good question. You don't use "*pointer(a)" -- the dereference is implied, so you don't need the "*", only "pointer(a)". When a function is called this way, type-checking of arguments can't be done at compile-time. A "typedef" shared by the functions in question would help with that. There's more information at the link at the very end of the function pointer section, just before the section "Strings (and why there's no such thing".
Rob F
Ok, thanks for the explanation.
Ian_K
A: 

c does not have a built in notion of lists or list comprehension, you have to set up an explicit loop over an array, and have to support the length of the list yourself.

Yes, this is wordier than the python way, but that is because python is handling the details for you.

Data structures that are reasonably well suited to handling notional "lists":

  • dynamic arrays (possibly wrapped in a struct to let you hold meta info like the current length and allocated length in the same place)
  • linked lists

If you choose an array based solution you will need to either

  1. keep track of the current length and pass it to the processing functions
  2. use a sentinel to mark the end of the data (which might mean using a larger data type to allow you to specify a sentinel that can not appear in the data)

linked lists can be processed node by node because the have a natural end.

dmckee
A: 
sambowry