¿Cómo puedo usar una matriz de punteros de función?

Respuestas:

194

Tiene un buen ejemplo aquí (matriz de punteros de función) , con la sintaxis detallada .

int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int (*p[4]) (int x, int y);

int main(void)
{
  int result;
  int i, j, op;

  p[0] = sum; /* address of sum() */
  p[1] = subtract; /* address of subtract() */
  p[2] = mul; /* address of mul() */
  p[3] = div; /* address of div() */
[...]

Para llamar a uno de esos punteros de función:

result = (*p[op]) (i, j); // op being the index of one of the four functions
VonC
fuente
3
Buena respuesta: sin embargo, debe extenderlo para mostrar cómo llamar a una de las funciones.
Jonathan Leffler
1
@crucifiedsoul "el lenguaje de programación C" escrito por Brian Kernighan y Dennis Ritchie? Podría ser, pero no lo tenía como referencia cuando escribí la respuesta hace tres años y medio. Entonces no lo sé.
VonC
12
Me gustaría agregar que puede inicializar p con(*p[4]) (int, int) {sum,substract,mul,div}
jiggunjer
1
@VonC: gran respuesta. +1 para los enlaces.
Destructor
@jiggunjer s / substract / substract /: p. Pero gracias por ese comentario, muy útil :). +1.
RastaJedi
41

Las respuestas anteriores pueden ayudarlo, pero es posible que también desee saber cómo utilizar la matriz de punteros de función.

void fun1()
{

}

void fun2()
{

}

void fun3()
{

}

void (*func_ptr[3])() = {fun1, fun2, fun3};

main()
{
    int option;


    printf("\nEnter function number you want");
    printf("\nYou should not enter other than 0 , 1, 2"); /* because we have only 3 functions */
    scanf("%d",&option);

    if((option>=0)&&(option<=2))
    { 
        (*func_ptr[option])();
    }

    return 0;
}

Solo puede asignar las direcciones de funciones con el mismo tipo de retorno y los mismos tipos de argumentos y ninguno de los argumentos a una única matriz de puntero de función.

También puede pasar argumentos como a continuación si todas las funciones anteriores tienen el mismo número de argumentos del mismo tipo.

  (*func_ptr[option])(argu1);

Nota: aquí en la matriz, la numeración de los punteros de función comenzará desde 0 igual que en las matrices generales. Entonces, en el ejemplo anterior, fun1se puede llamar if option = 0, fun2se puede llamar if option = 1 y fun3se puede llamar if option = 2.

Dudas de Manoj
fuente
Incluso para esta pequeña demostración, debe agregar una verificación para el valor de entrada, ya que el código apunta a un novato ... :-)
PhiLho
if ((opción <0) || (opción> 2)) {(* func_ptr [opción]) (); } Amigo, esto significa que se llama al método solo cuando el usuario escribe un índice no válido.
ljs
66
Esa es una buena respuesta, sin embargo, debe agregar paréntesis después de (* func_ptr [3]) para que sea un código válido.
Alex
Esta es una respuesta horriblemente mala. Debido a los paréntesis faltantes, este código ni siquiera se compila .
CL.
como dijo @Alex, simplemente cámbielo de (*func_ptr[3])a (*func_ptr[3])()y se compilará
dsaydon
9

Así es como puedes usarlo:

New_Fun.h

#ifndef NEW_FUN_H_
#define NEW_FUN_H_

#include <stdio.h>

typedef int speed;
speed fun(int x);

enum fp {
    f1, f2, f3, f4, f5
};

void F1();
void F2();
void F3();
void F4();
void F5();
#endif

New_Fun.c

#include "New_Fun.h"

speed fun(int x)
{
    int Vel;
    Vel = x;
    return Vel;
}

void F1()
{
    printf("From F1\n");
}

void F2()
{
    printf("From F2\n");
}

void F3()
{
    printf("From F3\n");
}

void F4()
{
    printf("From F4\n");
}

void F5()
{
    printf("From F5\n");
}

C Principal

#include <stdio.h>
#include "New_Fun.h"

int main()
{
    int (*F_P)(int y);
    void (*F_A[5])() = { F1, F2, F3, F4, F5 };    // if it is int the pointer incompatible is bound to happen
    int xyz, i;

    printf("Hello Function Pointer!\n");
    F_P = fun;
    xyz = F_P(5);
    printf("The Value is %d\n", xyz);
    //(*F_A[5]) = { F1, F2, F3, F4, F5 };
    for (i = 0; i < 5; i++)
    {
        F_A[i]();
    }
    printf("\n\n");
    F_A[f1]();
    F_A[f2]();
    F_A[f3]();
    F_A[f4]();
    return 0;
}

Espero que esto ayude a entender Function Pointer.

Rasmi Ranjan Nayak
fuente
La línea 15 de Main.c debería ser para (i = 0; i <5; i ++), ¿verdad?
user3116936
¿Por qué declaraste el enumerador fp?
Llegada el
@ Flecha: Creo que vi algunos de los códigos heredados donde lo hicieron de esa manera ... Y se ve muy hermoso. Simplemente elimine f1, f2 ...y, en lugar de, ingrese 'writefile, readfromfile ...' ... se vuelve más legible
Rasmi Ranjan Nayak
5

Esta "respuesta" es más una adición a la respuesta de VonC; simplemente señalando que la sintaxis se puede simplificar a través de un typedef, y se puede usar la inicialización agregada:

typedef int FUNC(int, int);

FUNC sum, subtract, mul, div;
FUNC *p[4] = { sum, subtract, mul, div };

int main(void)
{
    int result;
    int i = 2, j = 3, op = 2;  // 2: mul

    result = p[op](i, j);   // = 6
}

// maybe even in another file
int sum(int a, int b) { return a+b; }
int subtract(int a, int b) { return a-b; }
int mul(int a, int b) { return a*b; }
int div(int a, int b) { return a/b; }
MM
fuente
2

Oh, hay toneladas de ejemplos. Solo eche un vistazo a cualquier cosa dentro de glib o gtk. Puede ver el trabajo de los punteros de función en el trabajo allí todo el camino.

Aquí, por ejemplo, la inicialización del material gtk_button.


static void
gtk_button_class_init (GtkButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  object_class = (GtkObjectClass*) klass;
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;

  gobject_class->constructor = gtk_button_constructor;
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;

Y en gtkobject.h encontrarás las siguientes declaraciones:


struct _GtkObjectClass
{
  GInitiallyUnownedClass parent_class;

  /* Non overridable class methods to set and get per class arguments */
  void (*set_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);
  void (*get_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);

  /* Default signal handler for the ::destroy signal, which is
   *  invoked to request that references to the widget be dropped.
   *  If an object class overrides destroy() in order to perform class
   *  specific destruction then it must still invoke its superclass'
   *  implementation of the method after it is finished with its
   *  own cleanup. (See gtk_widget_real_destroy() for an example of
   *  how to do this).
   */
  void (*destroy)  (GtkObject *object);
};

El material (* set_arg) es un puntero para funcionar y, por ejemplo, se le puede asignar otra implementación en alguna clase derivada.

A menudo ves algo como esto

struct function_table {
   char *name;
   void (*some_fun)(int arg1, double arg2);
};

void function1(int  arg1, double arg2)....


struct function_table my_table [] = {
    {"function1", function1},
...

Para que pueda acceder a la tabla por su nombre y llamar a la función "asociada".

O tal vez usa una tabla hash en la que pone la función y la llama "por su nombre".

Saludos
Friedrich

Friedrich
fuente
¿Sería posible usar una tabla de función de este tipo para las funciones hash dentro de la implementación de la tabla hash? (Leer: dependencia circular involucrada).
Flavius ​​el
2

Puede usarlo de esta manera:

//! Define:
#define F_NUM 3
int (*pFunctions[F_NUM])(void * arg);

//! Initialise:
int someFunction(void * arg) {
    int a= *((int*)arg);
    return a*a;
}

pFunctions[0]= someFunction;

//! Use:
int someMethod(int idx, void * arg, int * result) {
    int done= 0;
    if (idx < F_NUM && pFunctions[idx] != NULL) {
        *result= pFunctions[idx](arg);
        done= 1;
    }
    return done;
}

int x= 2;
int z= 0;
someMethod(0, (void*)&x, &z);
assert(z == 4);
Peter Hirt
fuente
1

Este debería ser un ejemplo breve y simple de copiar y pegar código de las respuestas anteriores. Espero que esto ayude.

#include <iostream>
using namespace std;

#define DBG_PRINT(x) do { std::printf("Line:%-4d" "  %15s = %-10d\n", __LINE__, #x, x); } while(0);

void F0(){ printf("Print F%d\n", 0); }
void F1(){ printf("Print F%d\n", 1); }
void F2(){ printf("Print F%d\n", 2); }
void F3(){ printf("Print F%d\n", 3); }
void F4(){ printf("Print F%d\n", 4); }
void (*fArrVoid[N_FUNC])() = {F0, F1, F2, F3, F4};

int Sum(int a, int b){ return(a+b); }
int Sub(int a, int b){ return(a-b); }
int Mul(int a, int b){ return(a*b); }
int Div(int a, int b){ return(a/b); }
int (*fArrArgs[4])(int a, int b) = {Sum, Sub, Mul, Div};

int main(){
    for(int i = 0; i < 5; i++)  (*fArrVoid[i])();
    printf("\n");

    DBG_PRINT((*fArrArgs[0])(3,2))
    DBG_PRINT((*fArrArgs[1])(3,2))
    DBG_PRINT((*fArrArgs[2])(3,2))
    DBG_PRINT((*fArrArgs[3])(3,2))

    return(0);
}
nimig18
fuente
Si se trata de una copia y pegar de otros anwers, no estoy seguro de que añade ningún valor ...
Fabio dice Restablecer Monica
Sí, veo su punto, agregaré el valor esta noche actualmente en el trabajo.
nimig18
1

La solución más simple es dar la dirección del vector final que desea y modificarlo dentro de la función.

void calculation(double result[] ){  //do the calculation on result

   result[0] = 10+5;
   result[1] = 10 +6;
   .....
}

int main(){

    double result[10] = {0}; //this is the vector of the results

    calculation(result);  //this will modify result
}
Leonardo
fuente
0

Esta pregunta ya ha sido respondida con muy buenos ejemplos. El único ejemplo que puede faltar es uno en el que las funciones devuelven punteros. Escribí otro ejemplo con esto, y agregué muchos comentarios, en caso de que alguien lo encuentre útil:

#include <stdio.h>

char * func1(char *a) {
    *a = 'b';
    return a;
}

char * func2(char *a) {
    *a = 'c';
    return a;
}

int main() {
    char a = 'a';
    /* declare array of function pointers
     * the function pointer types are char * name(char *)
     * A pointer to this type of function would be just
     * put * before name, and parenthesis around *name:
     *   char * (*name)(char *)
     * An array of these pointers is the same with [x]
     */
    char * (*functions[2])(char *) = {func1, func2};
    printf("%c, ", a);
    /* the functions return a pointer, so I need to deference pointer
     * Thats why the * in front of the parenthesis (in case it confused you)
     */
    printf("%c, ", *(*functions[0])(&a)); 
    printf("%c\n", *(*functions[1])(&a));

    a = 'a';
    /* creating 'name' for a function pointer type
     * funcp is equivalent to type char *(*funcname)(char *)
     */
    typedef char *(*funcp)(char *);
    /* Now the declaration of the array of function pointers
     * becomes easier
     */
    funcp functions2[2] = {func1, func2};

    printf("%c, ", a);
    printf("%c, ", *(*functions2[0])(&a));
    printf("%c\n", *(*functions2[1])(&a));

    return 0;
}
Jay Medina
fuente
0

Este ejemplo simple para una matriz multidimensional con punteros de función ":

void one( int a, int b){    printf(" \n[ ONE ]  a =  %d   b = %d",a,b);}
void two( int a, int b){    printf(" \n[ TWO ]  a =  %d   b = %d",a,b);}
void three( int a, int b){    printf("\n [ THREE ]  a =  %d   b = %d",a,b);}
void four( int a, int b){    printf(" \n[ FOUR ]  a =  %d   b = %d",a,b);}
void five( int a, int b){    printf(" \n [ FIVE ]  a =  %d   b = %d",a,b);}
void(*p[2][2])(int,int)   ;
int main()
{
    int i,j;
    printf("multidimensional array with function pointers\n");

    p[0][0] = one;    p[0][1] = two;    p[1][0] = three;    p[1][1] = four;
    for (  i  = 1 ; i >=0; i--)
        for (  j  = 0 ; j <2; j++)
            (*p[i][j])( (i, i*j);
    return 0;
}
arun kumar
fuente