ฉันจะใช้ตัวชี้ฟังก์ชันอาร์เรย์ได้อย่างไร


คำตอบ:


194

คุณต้องเป็นตัวอย่างที่ดีที่นี่ (อาร์เรย์ของตัวชี้ฟังก์ชั่น)กับไวยากรณ์รายละเอียด

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

วิธีเรียกใช้พอยน์เตอร์ของฟังก์ชันเหล่านั้น:

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

3
คำตอบที่ดี - คุณควรขยายออกไปเพื่อแสดงวิธีเรียกใช้ฟังก์ชันใดฟังก์ชันหนึ่ง
Jonathan Leffler

1
@ crucifiedsoul "ภาษาการเขียนโปรแกรม C" เขียนโดย Brian Kernighan และ Dennis Ritchie? อาจเป็นได้ แต่ฉันไม่ได้เป็นข้อมูลอ้างอิงในขณะที่ฉันเขียนคำตอบเมื่อสามปีครึ่งที่ผ่านมา ดังนั้นฉันไม่รู้
VonC

12
ฉันต้องการเพิ่มคุณสามารถเริ่มต้น p ด้วย(*p[4]) (int, int) {sum,substract,mul,div}
jiggunjer

1
@VonC: คำตอบที่ดี +1 สำหรับลิงก์
Destructor

@ jiggunjer s / substract / subtract /: p แต่ขอบคุณสำหรับความคิดเห็นนั้นมีประโยชน์มาก :) +1
RastaJedi

41

คำตอบข้างต้นอาจช่วยคุณได้ แต่คุณอาจต้องการทราบวิธีใช้งานพอยน์เตอร์ของฟังก์ชัน

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

คุณสามารถกำหนดที่อยู่ของฟังก์ชั่นที่มีประเภทผลตอบแทนและประเภทอาร์กิวเมนต์เดียวกันและไม่มีข้อโต้แย้งไปยังอาร์เรย์ตัวชี้ฟังก์ชั่นเดียว

นอกจากนี้คุณยังสามารถส่งผ่านอาร์กิวเมนต์เช่นด้านล่างหากฟังก์ชันด้านบนทั้งหมดมีจำนวนอาร์กิวเมนต์เท่ากัน

  (*func_ptr[option])(argu1);

หมายเหตุ: ที่นี่ในอาเรย์ตัวเลขของตัวชี้ฟังก์ชันจะเริ่มจาก 0 เหมือนกับในอาร์เรย์ทั่วไป ดังนั้นในตัวอย่างข้างต้นfun1สามารถเรียกว่าถ้าตัวเลือก = 0 fun2สามารถเรียกได้ว่าถ้าตัวเลือก = 1 และfun3สามารถเรียกได้ว่าถ้าตัวเลือก = 2


แม้สำหรับการสาธิตนี้น้อยคุณควรเพิ่มการตรวจสอบค่าการป้อนข้อมูลตั้งแต่รหัสเป้าหมายมือใหม่ ... :-)
PhiLho

ถ้า ((ตัวเลือก <0) || (ตัวเลือก> 2)) {(* func_ptr [ตัวเลือก]) () } เพื่อนนี้หมายถึงวิธีการที่เรียกว่าเฉพาะเมื่อผู้ใช้พิมพ์ในดัชนีที่ไม่ถูกต้อง!
ljs

6
นั่นเป็นคำตอบที่ดี แต่คุณควรเพิ่มวงเล็บหลัง (* func_ptr [3]) เพื่อให้เป็นรหัสที่ถูกต้อง
Alex

นี่เป็นคำตอบที่ไม่ดีอย่างน่ากลัว เนื่องจากวงเล็บหายไปรหัสนี้จึงไม่สามารถคอมไพล์ได้
CL

เช่น @Alex พูดเพียงแค่เปลี่ยนจาก(*func_ptr[3])เป็น(*func_ptr[3])()และมันจะรวบรวม
dsaydon

9

นี่คือวิธีการใช้งาน:

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

ฉันหวังว่านี่จะช่วยในการทำความเข้าใจ Function Pointer.


บรรทัดที่ 15 ของ Main.c ควรเป็น (i = 0; i <5; i ++) ใช่ไหม
user3116936

ทำไมคุณถึงประกาศให้ fp enumerator
Arrrow

@Arrow: ฉันคิดว่าฉันเห็นบางส่วนของรหัสดั้งเดิมที่พวกเขาทำมันในแบบนั้น ... และมันก็ดูสวยงามมาก เพียงแค่ลบf1, f2 ...และแทนที่จากนั้นป้อน 'writefile, readfromfile ... ' ... มันจะกลายเป็น redable มากขึ้น
Rasmi Ranjan Nayak

5

"คำตอบ" นี้เป็นส่วนเพิ่มเติมของคำตอบของ VonC เพิ่งสังเกตว่าไวยากรณ์สามารถทำให้ง่ายขึ้นผ่าน typedef และการเริ่มต้นรวมสามารถใช้:

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

โอ้มีตัวอย่างมากมาย เพียงแค่ดูสิ่งใดในกะล่อนหรือ gtk คุณสามารถเห็นการทำงานของพอยน์เตอร์ฟังก์ชั่นในการทำงานที่นั่นตลอดทาง

ที่นี่เช่นการเริ่มต้นของสิ่ง 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;

และใน gtkobject.h คุณจะพบคำประกาศต่อไปนี้:


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) เป็นตัวชี้ไปยังฟังก์ชั่นและสิ่งนี้สามารถได้รับมอบหมายการดำเนินงานอื่นในบางระดับที่ได้รับ

บ่อยครั้งที่คุณเห็นอะไรเช่นนี้

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

ดังนั้นคุณสามารถเข้าถึงตารางโดยใช้ชื่อและเรียกใช้ฟังก์ชัน "ที่เกี่ยวข้อง"

หรือบางทีคุณอาจใช้ตารางแฮชที่คุณวางฟังก์ชั่นและเรียกมันว่า "ตามชื่อ"

ขอแสดงความนับถือ
ฟรีดริช


มันจะเป็นไปได้หรือไม่ที่ pssible จะใช้ function_table สำหรับฟังก์ชั่นการแฮชในการใช้ตารางแฮชเอง? (อ่าน: การพึ่งพาแบบวงกลมเกี่ยวข้องกัน)
Flavius

2

สามารถใช้งานในลักษณะนี้:

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

นี่ควรเป็นตัวอย่างสั้น ๆ ที่ง่ายและง่ายในการคัดลอกและวางโค้ด หวังว่านี่จะช่วยได้

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

ถ้าเป็นสำเนา & วางจากคำตอบอื่นฉันไม่แน่ใจว่ามันจะเพิ่มคุณค่าใด ๆ ...
Fabio พูดว่า Reinstate Monica

ใช่ฉันเห็นประเด็นของคุณแล้วฉันจะเพิ่มมูลค่าคืนนี้ในที่ทำงาน
nimig18

1

วิธีที่ง่ายที่สุดคือให้ที่อยู่ของเวกเตอร์สุดท้ายที่คุณต้องการและแก้ไขภายในฟังก์ชัน

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

คำถามนี้ได้รับการตอบแล้วด้วยตัวอย่างที่ดีมาก ตัวอย่างเดียวที่อาจหายไปคือตัวอย่างที่ฟังก์ชันส่งคืนพอยน์เตอร์ ฉันเขียนอีกตัวอย่างหนึ่งของสิ่งนี้และเพิ่มความคิดเห็นจำนวนมากในกรณีที่มีคนพบว่ามีประโยชน์:

#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

ตัวอย่างง่าย ๆ สำหรับอาร์เรย์หลายมิติพร้อมด้วยพอยน์เตอร์ฟังก์ชั่น ":

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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.