C: как применить последовательность переменных к функции? - PullRequest
3 голосов
/ 08 октября 2009

В C, есть ли способ вызвать функцию с аргументами, хранящимися в каком-либо массиве? Я новичок в C, я даже не уверен, правильно ли это, но, например ::

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: Какую структуру я должен использовать, когда длина элементов массива варьируется?

В Python это будет:

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)

Ответы [ 5 ]

2 голосов
/ 08 октября 2009

Возможно, в C есть переменные функции арности, но механизм неуклюжий и имеет определенные ограничения, а именно, должен быть хотя бы один фиксированный параметр, и вам необходимо иметь возможность получать данные из фиксированных параметров или из переменной. Сами параметры, где конец списка переменных.

Более типичное решение, которое использует сильные стороны С, а не его слабые стороны, является чем-то вроде этого примера. ( Обновлено с помощью функциональных указателей .)

#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;
}
2 голосов
/ 08 октября 2009

Не совсем, нет.

Лучшим способом сделать это в C было бы определение всех ваших функций, имеющих одинаковую сигнатуру, например:

void f0(int size, int elements[])

и затем передайте массивы соответствующего размера вашим функциям.

// 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]));
0 голосов
/ 08 октября 2009
#include <stdio.h> 

void f0(int a              ){ printf("f0(%i)\n",      a    ); }
void f1(int a, int b       ){ printf("f1(%i,%i)\n",   a,b  ); }
void f2(int a, int b, int c){ printf("f2(%i,%i,%i)\n",a,b,c); }

typedef void (*f_arg1)(int);
typedef void (*f_arg2)(int,int);
typedef void (*f_arg3)(int,int,int);

struct fn_call {
  f_arg1 fn;
  int arg_num;
  int *args;
} array[] = {  { (f_arg1)f0, 1, (int[]){5}               },
               { (f_arg1)f1, 2, (int[]){-23, 5}          },
               { (f_arg1)f2, 3, (int[]){0, 1, 2}         },
               { (f_arg1)f2, 3, (int[]){1235, 111, 4234} },
               { (f_arg1)f0, 1, (int[]){22}              }   };

void apply( struct fn_call *call ){
  switch( call->arg_num ){
  case 1: ((f_arg1)call->fn)( call->args[0] );                  break;
  case 2: ((f_arg2)call->fn)( call->args[0], call->args[1] );   break;
  case 3: ((f_arg3)call->fn)( call->args[0], call->args[1], call->args[2] );
  }
}

int main(){
  for(unsigned i=0; i<sizeof(array); i++)  apply( &array[i] );
}

Результат:

f0(5)
f1(-23,5)
f2(0,1,2)
f2(1235,111,4234)
f0(22)
0 голосов
/ 08 октября 2009

c не имеет встроенного понятия списков или понимания списка , вы должны установить явный цикл для массива и сами должны поддерживать длину списка.

Да, это более многословно, чем в Python, но это потому, что Python обрабатывает детали для вас.

Структуры данных, которые достаточно хорошо подходят для обработки условных «списков»:

  • динамические массивы (возможно, обернутые в struct, чтобы вы могли хранить метаинформацию, например текущую длину и выделенную длину в одном месте)
  • связанные списки

Если вы выбираете решение на основе массива, вам нужно будет либо

  1. отслеживать текущую длину и передавать ее функциям обработки
  2. использовать часовой для обозначения конца данных (что может означать использование большего типа данных, чтобы вы могли указать часовой, который не может отображаться в данных)

связанные списки могут обрабатываться узел за узлом, потому что имеют естественный конец.

0 голосов
/ 08 октября 2009

Я думаю, возможно, вы просто хотите:

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

Для вызова функции из ее указателя в C требуется только оператор вызова функции, который является скобками.

Возможно, полезная ссылка: http://boredzo.org/pointers/

...