Bir dizi işlev işaretçisi nasıl kullanabilirim?


Yanıtlar:


194

Sen iyi bir örnek var burada (Fonksiyon işaretçileri Array) ile, detaylı sözdizimi .

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() */
[...]

Bu işlev işaretçilerinden birini aramak için:

result = (*p[op]) (i, j); // op being the index of one of the four functions

3
İyi cevap - yine de işlevlerden birini nasıl arayacağınızı göstermek için genişletmelisiniz.
Jonathan Leffler

1
@crucifiedsoul Brian Kernighan ve Dennis Ritchie tarafından yazılan "C Programlama Dili"? Olabilir, ama üç buçuk yıl önce cevabı yazdığım sırada referans olarak almadım. Yani bilmiyorum.
VonC

12
P ile (*p[4]) (int, int) {sum,substract,mul,div}
başlayabilmenizi isterim

1
@VonC: harika cevap. Bağlantılar için +1.
Destructor

@jiggunjer s / substract / çıkarma /: s. Ama bu yorum için teşekkürler, çok yararlı :). +1.
RastaJedi

41

Yukarıdaki yanıtlar size yardımcı olabilir, ancak işlev işaretçileri dizisinin nasıl kullanılacağını da bilmek isteyebilirsiniz.

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;
}

Yalnızca aynı dönüş türüne, aynı bağımsız değişken türlerine ve bağımsız değişkenlere sahip işlevlerin adreslerini tek bir işlev işaretçisi dizisine atayabilirsiniz.

Yukarıdaki işlevlerin tümü aynı türde aynı sayıda bağımsız değişkene sahipse aşağıdaki gibi bağımsız değişkenler de iletebilirsiniz.

  (*func_ptr[option])(argu1);

Not: Burada dizide işlev işaretleyicilerinin numaralandırılması genel dizilerde olduğu gibi 0'dan başlayacaktır. Yukarıdaki örnekte fun1seçenek = 0 fun2ise çağrılabilir, seçenek = 1 fun3ise çağrılabilir ve seçenek = 2 ise çağrılabilir.


Bu küçük demo için bile, giriş değeri için bir kontrol eklemelisiniz, çünkü kod bir acemi hedefliyor ... :-)
PhiLho

if ((seçenek <0) || (seçenek> 2)) {(* func_ptr [seçenek]) (); } Dostum, bu yöntem yalnızca kullanıcı geçersiz bir dizin yazdığında çağrılır!
ljs

6
Bu iyi bir yanıttır, ancak geçerli kodu yapmak için (* func_ptr [3]) öğesinden sonra parantez eklemeniz gerekir.
Alex,

Bu çok kötü bir cevap. Eksik parantez nedeniyle, bu kod bile derlenmez .
CL.

@Alex Dediğim gibi sadece onu değiştirmek (*func_ptr[3])için (*func_ptr[3])()ve derlenmiş olacak
dsaydon

9

Bunu nasıl kullanabileceğiniz aşağıda açıklanmıştır:

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");
}

main.c

#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;
}

Umarım bu anlamada yardımcı olur Function Pointer.


Main.c satır 15 (i = 0; i <5; i ++) için olmalı, değil mi?
user3116936

Neden fp numaralandırıcısını beyan ettiniz?
17:50

@Arrrow: Sanırım bu şekilde yaptıkları bazı eski kodları gördüm ... Ve çok güzel görünüyor. Sadece kaldırın f1, f2 ...ve yerine 'writefile, readfromfile ...' ... yazın. Daha kolay okunabilir hale geliyor
Ranjan Nayak

5

Bu "cevap" daha çok VonC'nin cevabına bir zeyilname niteliğindedir; sözdiziminin bir typedef ile basitleştirilebildiğini ve toplu başlatmanın kullanılabileceğini not edin:

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; }

2

Oh, tonlarca örnek var. Sadece glib veya gtk içindeki her şeye bir göz atın. Fonksiyon göstergelerinin çalışmalarını orada görebilirsiniz.

Burada, örneğin gtk_button öğelerinin başlatılması.


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;

Ve gtkobject.h dosyasında aşağıdaki bildirimleri bulabilirsiniz:


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);
};

(* Set_arg) öğesi, işlev gösterecek bir işaretçidir ve buna türetilmiş bir sınıfta başka bir uygulama atanabilir.

Genellikle böyle bir şey görürsünüz

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},
...

Böylece tabloya adıyla ulaşabilir ve "ilişkili" işlevini çağırabilirsiniz.

Ya da belki fonksiyonu koyduğunuz ve "isimle" olarak adlandırdığınız bir karma tablosu kullanırsınız.

Saygılarımızla
Friedrich


Karma tablo uygulamasının kendisinde karma işlevler için böyle bir function_table kullanmak kullanılabilir mi? (Oku: Dairesel bağımlılık söz konusudur).
Flavius

2

Bunu şu şekilde kullanabilir:

//! 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);

1

Bu, yukarıdaki yanıtların kısa ve basit bir kopyala ve yapıştır kod parçası örneği olmalıdır. Umarım bu yardımcı olur.

#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);
}

Diğer anwers kopya ve yapıştır ise, herhangi bir değer kattığından emin değilim ...
Fabio diyor Reinstate Monica

Evet, görüşünüzü anlıyorum, şu anda işyerinde bu değeri ekleyeceğim.
nimig18

1

En basit çözüm, istediğiniz son vektörün adresini vermek ve fonksiyon içinde değiştirmektir.

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
}

0

Bu soru çok iyi örneklerle zaten cevaplanmıştır. Eksik olabilecek tek örnek, işlevlerin işaretçiler döndürdüğü örnektir. Bununla bir örnek daha yazdım ve birisinin yararlı bulması durumunda birçok yorum ekledim:

#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;
}

0

İşlev işaretçileri olan çok boyutlu dizi için bu basit örnek ":

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.